blob: 0f3d0e8e5020750dd0a087fc237d5841fbaf883a [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 Vaskoee385fa2016-10-19 15:51:36 +02002191 const char *id, *mod_name, *name, *pred_name;
2192 int r, ret, mod_name_len, nam_len, is_relative = -1;
2193 int has_predicate, last_parsed, val_len, pred_name_len, last_has_pred;
Michal Vasko238bd2f2016-03-23 09:39:01 +01002194 struct lyd_node *sibling, *last_match = NULL;
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002195 struct lyd_node_leaf_list *llist;
Michal Vasko22448d32016-03-16 13:17:29 +01002196 const struct lys_module *prefix_mod, *prev_mod;
2197 struct ly_ctx *ctx;
2198
2199 assert(nodeid && start && parsed);
2200
2201 ctx = start->schema->module->ctx;
2202 id = nodeid;
2203
2204 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 +01002205 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002206 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002207 return NULL;
2208 }
2209 id += r;
2210 /* add it to parsed only after the data node was actually found */
2211 last_parsed = r;
2212
2213 if (is_relative) {
2214 prev_mod = start->schema->module;
Michal Vasko22448d32016-03-16 13:17:29 +01002215 start = start->child;
2216 } else {
2217 for (; start->parent; start = start->parent);
Michal Vasko22448d32016-03-16 13:17:29 +01002218 prev_mod = start->schema->module;
2219 }
2220
2221 while (1) {
2222 LY_TREE_FOR(start, sibling) {
Michal Vasko945b96b2016-10-18 11:49:12 +02002223 /* RPC/action data check, return simply invalid argument, because the data tree is invalid */
Michal Vasko2411b942016-03-23 13:50:03 +01002224 if (lys_parent(sibling->schema)) {
2225 if (options & LYD_PATH_OPT_OUTPUT) {
2226 if (lys_parent(sibling->schema)->nodetype == LYS_INPUT) {
Michal Vaskob7246892016-04-19 10:37:35 +02002227 LOGERR(LY_EINVAL, "Provided data tree includes some RPC input nodes (%s).", sibling->schema->name);
Michal Vasko2411b942016-03-23 13:50:03 +01002228 *parsed = -1;
2229 return NULL;
2230 }
2231 } else {
2232 if (lys_parent(sibling->schema)->nodetype == LYS_OUTPUT) {
Michal Vaskob7246892016-04-19 10:37:35 +02002233 LOGERR(LY_EINVAL, "Provided data tree includes some RPC output nodes (%s).", sibling->schema->name);
Michal Vasko2411b942016-03-23 13:50:03 +01002234 *parsed = -1;
2235 return NULL;
2236 }
2237 }
2238 }
2239
Michal Vasko22448d32016-03-16 13:17:29 +01002240 /* name match */
2241 if (!strncmp(name, sibling->schema->name, nam_len) && !sibling->schema->name[nam_len]) {
2242
2243 /* module check */
2244 if (mod_name) {
Michal Vasko971a3ca2016-04-01 13:09:29 +02002245 if (mod_name_len > LY_BUF_SIZE - 1) {
Michal Vasko22448d32016-03-16 13:17:29 +01002246 LOGINT;
Michal Vasko238bd2f2016-03-23 09:39:01 +01002247 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002248 return NULL;
2249 }
Michal Vasko971a3ca2016-04-01 13:09:29 +02002250
2251 if (ly_buf_used && module_name[0]) {
2252 buf_backup = strndup(module_name, LY_BUF_SIZE - 1);
2253 }
2254 ly_buf_used++;
2255
Michal Vaskodf3f1ab2016-04-01 15:07:22 +02002256 memmove(module_name, mod_name, mod_name_len);
Michal Vasko22448d32016-03-16 13:17:29 +01002257 module_name[mod_name_len] = '\0';
2258 /* will also find an augment module */
2259 prefix_mod = ly_ctx_get_module(ctx, module_name, NULL);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002260
2261 if (buf_backup) {
2262 /* return previous internal buffer content */
Michal Vasko888a1292016-04-05 12:08:54 +02002263 strncpy(module_name, buf_backup, LY_BUF_SIZE - 1);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002264 free(buf_backup);
2265 buf_backup = NULL;
2266 }
2267 ly_buf_used--;
2268
Michal Vasko22448d32016-03-16 13:17:29 +01002269 if (!prefix_mod) {
Michal Vasko10728b52016-04-07 14:26:29 +02002270 str = strndup(nodeid, (mod_name + mod_name_len) - nodeid);
2271 LOGVAL(LYE_PATH_INMOD, LY_VLOG_STR, str);
2272 free(str);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002273 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002274 return NULL;
2275 }
2276 } else {
2277 prefix_mod = prev_mod;
2278 }
2279 if (prefix_mod != lys_node_module(sibling->schema)) {
2280 continue;
2281 }
2282
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002283 /* leaf-list, did we find it with the correct value or not? */
Michal Vasko22448d32016-03-16 13:17:29 +01002284 if (sibling->schema->nodetype == LYS_LEAFLIST) {
Michal Vaskoee385fa2016-10-19 15:51:36 +02002285 last_has_pred = 0;
Michal Vaskoacb87b62016-10-19 11:33:55 +02002286 if (has_predicate) {
Michal Vaskoee385fa2016-10-19 15:51:36 +02002287 if ((r = parse_schema_json_predicate(id, &pred_name, &pred_name_len, &llist_value, &val_len, &last_has_pred)) < 1) {
Michal Vaskoacb87b62016-10-19 11:33:55 +02002288 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
2289 *parsed = -1;
2290 return NULL;
2291 }
Michal Vaskoee385fa2016-10-19 15:51:36 +02002292 if ((pred_name[0] != '.') || (pred_name_len != 1)) {
2293 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[1], id + 1);
2294 *parsed = -1;
2295 return NULL;
2296 }
Michal Vaskoacb87b62016-10-19 11:33:55 +02002297 } else {
2298 r = 0;
2299 if (llist_value) {
2300 val_len = strlen(llist_value);
2301 } else {
2302 val_len = 0;
2303 }
2304 }
2305
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002306 llist = (struct lyd_node_leaf_list *)sibling;
Michal Vaskoacb87b62016-10-19 11:33:55 +02002307 if ((!val_len && llist->value_str && llist->value_str[0])
2308 || (val_len && (strncmp(llist_value, llist->value_str, val_len) || llist->value_str[val_len]))) {
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002309 continue;
2310 }
Michal Vaskoacb87b62016-10-19 11:33:55 +02002311 id += r;
2312 last_parsed += r;
Michal Vaskoee385fa2016-10-19 15:51:36 +02002313 has_predicate = last_has_pred;
Michal Vaskoacb87b62016-10-19 11:33:55 +02002314
Radek Krejci45826012016-08-24 15:07:57 +02002315 } else if (sibling->schema->nodetype == LYS_LIST) {
2316 /* list, we need predicates'n'stuff then */
Michal Vasko22448d32016-03-16 13:17:29 +01002317 r = 0;
2318 if (!has_predicate) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002319 LOGVAL(LYE_PATH_MISSKEY, LY_VLOG_NONE, NULL, name);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002320 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002321 return NULL;
2322 }
2323 ret = resolve_partial_json_data_list_predicate(id, name, sibling, &r);
2324 if (ret == -1) {
Michal Vasko238bd2f2016-03-23 09:39:01 +01002325 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002326 return NULL;
2327 } else if (ret == 1) {
2328 /* this list instance does not match */
2329 continue;
2330 }
2331 id += r;
2332 last_parsed += r;
2333 }
2334
2335 *parsed += last_parsed;
2336
2337 /* the result node? */
2338 if (!id[0]) {
2339 return sibling;
2340 }
2341
2342 /* move down the tree, if possible */
Radek Krejcibf2abff2016-08-23 15:51:52 +02002343 if (sibling->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002344 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002345 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002346 return NULL;
2347 }
Michal Vaskoc6c52cf2016-03-29 11:53:04 +02002348 last_match = sibling;
Michal Vasko22448d32016-03-16 13:17:29 +01002349 start = sibling->child;
2350 if (start) {
2351 prev_mod = start->schema->module;
2352 }
2353 break;
2354 }
2355 }
2356
2357 /* no match, return last match */
2358 if (!sibling) {
2359 return last_match;
2360 }
2361
2362 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 +01002363 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002364 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002365 return NULL;
2366 }
2367 id += r;
2368 last_parsed = r;
2369 }
2370
2371 /* cannot get here */
2372 LOGINT;
Michal Vasko238bd2f2016-03-23 09:39:01 +01002373 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002374 return NULL;
2375}
2376
Michal Vasko3edeaf72016-02-11 13:17:43 +01002377/**
Michal Vasko730dfdf2015-08-11 14:48:05 +02002378 * @brief Resolves length or range intervals. Does not log.
Michal Vaskoaeb51802016-04-11 10:58:47 +02002379 * Syntax is assumed to be correct, *ret MUST be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002380 *
Michal Vaskoaeb51802016-04-11 10:58:47 +02002381 * @param[in] str_restr Restriction as a string.
2382 * @param[in] type Type of the restriction.
2383 * @param[out] ret Final interval structure that starts with
2384 * the interval of the initial type, continues with intervals
2385 * of any superior types derived from the initial one, and
2386 * finishes with intervals from our \p type.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002387 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002388 * @return EXIT_SUCCESS on succes, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002389 */
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002390int
Michal Vaskoaeb51802016-04-11 10:58:47 +02002391resolve_len_ran_interval(const char *str_restr, struct lys_type *type, struct len_ran_intv **ret)
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002392{
2393 /* 0 - unsigned, 1 - signed, 2 - floating point */
Michal Vaskoaeb51802016-04-11 10:58:47 +02002394 int kind;
Michal Vasko4d1f0482016-09-19 14:35:06 +02002395 int64_t local_smin, local_smax, local_fmin, local_fmax;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002396 uint64_t local_umin, local_umax;
Michal Vasko4d1f0482016-09-19 14:35:06 +02002397 uint8_t local_fdig;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002398 const char *seg_ptr, *ptr;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002399 struct len_ran_intv *local_intv = NULL, *tmp_local_intv = NULL, *tmp_intv, *intv = NULL;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002400
2401 switch (type->base) {
2402 case LY_TYPE_BINARY:
2403 kind = 0;
2404 local_umin = 0;
2405 local_umax = 18446744073709551615UL;
2406
2407 if (!str_restr && type->info.binary.length) {
2408 str_restr = type->info.binary.length->expr;
2409 }
2410 break;
2411 case LY_TYPE_DEC64:
2412 kind = 2;
Michal Vasko4d1f0482016-09-19 14:35:06 +02002413 local_fmin = __INT64_C(-9223372036854775807) - __INT64_C(1);
2414 local_fmax = __INT64_C(9223372036854775807);
2415 local_fdig = type->info.dec64.dig;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002416
2417 if (!str_restr && type->info.dec64.range) {
2418 str_restr = type->info.dec64.range->expr;
2419 }
2420 break;
2421 case LY_TYPE_INT8:
2422 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002423 local_smin = __INT64_C(-128);
2424 local_smax = __INT64_C(127);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002425
2426 if (!str_restr && type->info.num.range) {
2427 str_restr = type->info.num.range->expr;
2428 }
2429 break;
2430 case LY_TYPE_INT16:
2431 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002432 local_smin = __INT64_C(-32768);
2433 local_smax = __INT64_C(32767);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002434
2435 if (!str_restr && type->info.num.range) {
2436 str_restr = type->info.num.range->expr;
2437 }
2438 break;
2439 case LY_TYPE_INT32:
2440 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002441 local_smin = __INT64_C(-2147483648);
2442 local_smax = __INT64_C(2147483647);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002443
2444 if (!str_restr && type->info.num.range) {
2445 str_restr = type->info.num.range->expr;
2446 }
2447 break;
2448 case LY_TYPE_INT64:
2449 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002450 local_smin = __INT64_C(-9223372036854775807) - __INT64_C(1);
2451 local_smax = __INT64_C(9223372036854775807);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002452
2453 if (!str_restr && type->info.num.range) {
2454 str_restr = type->info.num.range->expr;
2455 }
2456 break;
2457 case LY_TYPE_UINT8:
2458 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002459 local_umin = __UINT64_C(0);
2460 local_umax = __UINT64_C(255);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002461
2462 if (!str_restr && type->info.num.range) {
2463 str_restr = type->info.num.range->expr;
2464 }
2465 break;
2466 case LY_TYPE_UINT16:
2467 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002468 local_umin = __UINT64_C(0);
2469 local_umax = __UINT64_C(65535);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002470
2471 if (!str_restr && type->info.num.range) {
2472 str_restr = type->info.num.range->expr;
2473 }
2474 break;
2475 case LY_TYPE_UINT32:
2476 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002477 local_umin = __UINT64_C(0);
2478 local_umax = __UINT64_C(4294967295);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002479
2480 if (!str_restr && type->info.num.range) {
2481 str_restr = type->info.num.range->expr;
2482 }
2483 break;
2484 case LY_TYPE_UINT64:
2485 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002486 local_umin = __UINT64_C(0);
2487 local_umax = __UINT64_C(18446744073709551615);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002488
2489 if (!str_restr && type->info.num.range) {
2490 str_restr = type->info.num.range->expr;
2491 }
2492 break;
2493 case LY_TYPE_STRING:
2494 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002495 local_umin = __UINT64_C(0);
2496 local_umax = __UINT64_C(18446744073709551615);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002497
2498 if (!str_restr && type->info.str.length) {
2499 str_restr = type->info.str.length->expr;
2500 }
2501 break;
2502 default:
2503 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002504 return -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002505 }
2506
2507 /* process superior types */
Michal Vaskoaeb51802016-04-11 10:58:47 +02002508 if (type->der) {
2509 if (resolve_len_ran_interval(NULL, &type->der->type, &intv)) {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002510 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002511 return -1;
Michal Vasko0c888fd2015-08-11 15:54:08 +02002512 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002513 assert(!intv || (intv->kind == kind));
2514 }
2515
2516 if (!str_restr) {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002517 /* we do not have any restriction, return superior ones */
2518 *ret = intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002519 return EXIT_SUCCESS;
2520 }
2521
2522 /* adjust local min and max */
2523 if (intv) {
2524 tmp_intv = intv;
2525
2526 if (kind == 0) {
2527 local_umin = tmp_intv->value.uval.min;
2528 } else if (kind == 1) {
2529 local_smin = tmp_intv->value.sval.min;
2530 } else if (kind == 2) {
2531 local_fmin = tmp_intv->value.fval.min;
2532 }
2533
2534 while (tmp_intv->next) {
2535 tmp_intv = tmp_intv->next;
2536 }
2537
2538 if (kind == 0) {
2539 local_umax = tmp_intv->value.uval.max;
2540 } else if (kind == 1) {
2541 local_smax = tmp_intv->value.sval.max;
2542 } else if (kind == 2) {
2543 local_fmax = tmp_intv->value.fval.max;
2544 }
2545 }
2546
2547 /* finally parse our restriction */
2548 seg_ptr = str_restr;
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002549 tmp_intv = NULL;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002550 while (1) {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002551 if (!tmp_local_intv) {
2552 assert(!local_intv);
2553 local_intv = malloc(sizeof *local_intv);
2554 tmp_local_intv = local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002555 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002556 tmp_local_intv->next = malloc(sizeof *tmp_local_intv);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002557 tmp_local_intv = tmp_local_intv->next;
2558 }
Michal Vasko253035f2015-12-17 16:58:13 +01002559 if (!tmp_local_intv) {
2560 LOGMEM;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002561 goto error;
Michal Vasko253035f2015-12-17 16:58:13 +01002562 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002563
2564 tmp_local_intv->kind = kind;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002565 tmp_local_intv->type = type;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002566 tmp_local_intv->next = NULL;
2567
2568 /* min */
2569 ptr = seg_ptr;
2570 while (isspace(ptr[0])) {
2571 ++ptr;
2572 }
2573 if (isdigit(ptr[0]) || (ptr[0] == '+') || (ptr[0] == '-')) {
2574 if (kind == 0) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002575 tmp_local_intv->value.uval.min = strtol(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002576 } else if (kind == 1) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002577 tmp_local_intv->value.sval.min = strtol(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002578 } else if (kind == 2) {
Michal Vaskod24dd012016-09-30 12:20:22 +02002579 if (parse_range_dec64(&ptr, local_fdig, &tmp_local_intv->value.fval.min)) {
2580 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, ptr, "range");
2581 goto error;
2582 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002583 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002584 } else if (!strncmp(ptr, "min", 3)) {
2585 if (kind == 0) {
2586 tmp_local_intv->value.uval.min = local_umin;
2587 } else if (kind == 1) {
2588 tmp_local_intv->value.sval.min = local_smin;
2589 } else if (kind == 2) {
2590 tmp_local_intv->value.fval.min = local_fmin;
2591 }
2592
2593 ptr += 3;
2594 } else if (!strncmp(ptr, "max", 3)) {
2595 if (kind == 0) {
2596 tmp_local_intv->value.uval.min = local_umax;
2597 } else if (kind == 1) {
2598 tmp_local_intv->value.sval.min = local_smax;
2599 } else if (kind == 2) {
2600 tmp_local_intv->value.fval.min = local_fmax;
2601 }
2602
2603 ptr += 3;
2604 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002605 LOGINT;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002606 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002607 }
2608
2609 while (isspace(ptr[0])) {
2610 ptr++;
2611 }
2612
2613 /* no interval or interval */
2614 if ((ptr[0] == '|') || !ptr[0]) {
2615 if (kind == 0) {
2616 tmp_local_intv->value.uval.max = tmp_local_intv->value.uval.min;
2617 } else if (kind == 1) {
2618 tmp_local_intv->value.sval.max = tmp_local_intv->value.sval.min;
2619 } else if (kind == 2) {
2620 tmp_local_intv->value.fval.max = tmp_local_intv->value.fval.min;
2621 }
2622 } else if (!strncmp(ptr, "..", 2)) {
2623 /* skip ".." */
2624 ptr += 2;
2625 while (isspace(ptr[0])) {
2626 ++ptr;
2627 }
2628
2629 /* max */
2630 if (isdigit(ptr[0]) || (ptr[0] == '+') || (ptr[0] == '-')) {
2631 if (kind == 0) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002632 tmp_local_intv->value.uval.max = strtol(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002633 } else if (kind == 1) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002634 tmp_local_intv->value.sval.max = strtol(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002635 } else if (kind == 2) {
Michal Vaskod24dd012016-09-30 12:20:22 +02002636 if (parse_range_dec64(&ptr, local_fdig, &tmp_local_intv->value.fval.max)) {
2637 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, ptr, "range");
2638 goto error;
2639 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002640 }
2641 } else if (!strncmp(ptr, "max", 3)) {
2642 if (kind == 0) {
2643 tmp_local_intv->value.uval.max = local_umax;
2644 } else if (kind == 1) {
2645 tmp_local_intv->value.sval.max = local_smax;
2646 } else if (kind == 2) {
2647 tmp_local_intv->value.fval.max = local_fmax;
2648 }
2649 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002650 LOGINT;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002651 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002652 }
2653 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002654 LOGINT;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002655 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002656 }
2657
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002658 /* check min and max in correct order*/
2659 if (kind == 0) {
2660 /* current segment */
2661 if (tmp_local_intv->value.uval.min > tmp_local_intv->value.uval.max) {
2662 goto error;
2663 }
2664 if (tmp_local_intv->value.uval.min < local_umin || tmp_local_intv->value.uval.max > local_umax) {
2665 goto error;
2666 }
2667 /* segments sholud be ascending order */
Pavol Vican69f62c92016-08-30 09:06:25 +02002668 if (tmp_intv && (tmp_intv->value.uval.max >= tmp_local_intv->value.uval.min)) {
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002669 goto error;
2670 }
2671 } else if (kind == 1) {
2672 if (tmp_local_intv->value.sval.min > tmp_local_intv->value.sval.max) {
2673 goto error;
2674 }
2675 if (tmp_local_intv->value.sval.min < local_smin || tmp_local_intv->value.sval.max > local_smax) {
2676 goto error;
2677 }
Pavol Vican69f62c92016-08-30 09:06:25 +02002678 if (tmp_intv && (tmp_intv->value.sval.max >= tmp_local_intv->value.sval.min)) {
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002679 goto error;
2680 }
2681 } else if (kind == 2) {
2682 if (tmp_local_intv->value.fval.min > tmp_local_intv->value.fval.max) {
2683 goto error;
2684 }
2685 if (tmp_local_intv->value.fval.min < local_fmin || tmp_local_intv->value.fval.max > local_fmax) {
2686 goto error;
2687 }
Pavol Vican69f62c92016-08-30 09:06:25 +02002688 if (tmp_intv && (tmp_intv->value.fval.max >= tmp_local_intv->value.fval.min)) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002689 /* fraction-digits value is always the same (it cannot be changed in derived types) */
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002690 goto error;
2691 }
2692 }
2693
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002694 /* next segment (next OR) */
2695 seg_ptr = strchr(seg_ptr, '|');
2696 if (!seg_ptr) {
2697 break;
2698 }
2699 seg_ptr++;
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002700 tmp_intv = tmp_local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002701 }
2702
2703 /* check local restrictions against superior ones */
2704 if (intv) {
2705 tmp_intv = intv;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002706 tmp_local_intv = local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002707
2708 while (tmp_local_intv && tmp_intv) {
2709 /* reuse local variables */
2710 if (kind == 0) {
2711 local_umin = tmp_local_intv->value.uval.min;
2712 local_umax = tmp_local_intv->value.uval.max;
2713
2714 /* it must be in this interval */
2715 if ((local_umin >= tmp_intv->value.uval.min) && (local_umin <= tmp_intv->value.uval.max)) {
2716 /* this interval is covered, next one */
2717 if (local_umax <= tmp_intv->value.uval.max) {
2718 tmp_local_intv = tmp_local_intv->next;
2719 continue;
2720 /* ascending order of restrictions -> fail */
2721 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002722 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002723 }
2724 }
2725 } else if (kind == 1) {
2726 local_smin = tmp_local_intv->value.sval.min;
2727 local_smax = tmp_local_intv->value.sval.max;
2728
2729 if ((local_smin >= tmp_intv->value.sval.min) && (local_smin <= tmp_intv->value.sval.max)) {
2730 if (local_smax <= tmp_intv->value.sval.max) {
2731 tmp_local_intv = tmp_local_intv->next;
2732 continue;
2733 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002734 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002735 }
2736 }
2737 } else if (kind == 2) {
2738 local_fmin = tmp_local_intv->value.fval.min;
2739 local_fmax = tmp_local_intv->value.fval.max;
2740
Michal Vasko4d1f0482016-09-19 14:35:06 +02002741 if ((dec64cmp(local_fmin, local_fdig, tmp_intv->value.fval.min, local_fdig) > -1)
Pavol Vican3c8ee2b2016-09-29 13:18:13 +02002742 && (dec64cmp(local_fmin, local_fdig, tmp_intv->value.fval.max, local_fdig) < 1)) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002743 if (dec64cmp(local_fmax, local_fdig, tmp_intv->value.fval.max, local_fdig) < 1) {
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002744 tmp_local_intv = tmp_local_intv->next;
2745 continue;
2746 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002747 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002748 }
2749 }
2750 }
2751
2752 tmp_intv = tmp_intv->next;
2753 }
2754
2755 /* some interval left uncovered -> fail */
2756 if (tmp_local_intv) {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002757 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002758 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002759 }
2760
Michal Vaskoaeb51802016-04-11 10:58:47 +02002761 /* append the local intervals to all the intervals of the superior types, return it all */
2762 if (intv) {
2763 for (tmp_intv = intv; tmp_intv->next; tmp_intv = tmp_intv->next);
2764 tmp_intv->next = local_intv;
2765 } else {
2766 intv = local_intv;
2767 }
2768 *ret = intv;
2769
2770 return EXIT_SUCCESS;
2771
2772error:
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002773 while (intv) {
2774 tmp_intv = intv->next;
2775 free(intv);
2776 intv = tmp_intv;
2777 }
Michal Vaskoaeb51802016-04-11 10:58:47 +02002778 while (local_intv) {
2779 tmp_local_intv = local_intv->next;
2780 free(local_intv);
2781 local_intv = tmp_local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002782 }
2783
Michal Vaskoaeb51802016-04-11 10:58:47 +02002784 return -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002785}
2786
Michal Vasko730dfdf2015-08-11 14:48:05 +02002787/**
Michal Vasko01c6fd22016-05-20 11:43:05 +02002788 * @brief Resolve a typedef, return only resolved typedefs if derived. If leafref, it must be
2789 * resolved for this function to return it. Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002790 *
2791 * @param[in] name Typedef name.
Michal Vasko1dca6882015-10-22 14:29:42 +02002792 * @param[in] mod_name Typedef name module name.
2793 * @param[in] module Main module.
2794 * @param[in] parent Parent of the resolved type definition.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002795 * @param[out] ret Pointer to the resolved typedef. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002796 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002797 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002798 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002799int
Michal Vasko1e62a092015-12-01 12:27:20 +01002800resolve_superior_type(const char *name, const char *mod_name, const struct lys_module *module,
2801 const struct lys_node *parent, struct lys_tpdf **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002802{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002803 int i, j;
Michal Vasko01c6fd22016-05-20 11:43:05 +02002804 struct lys_tpdf *tpdf, *match;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002805 int tpdf_size;
2806
Michal Vasko1dca6882015-10-22 14:29:42 +02002807 if (!mod_name) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002808 /* no prefix, try built-in types */
2809 for (i = 1; i < LY_DATA_TYPE_COUNT; i++) {
2810 if (!strcmp(ly_types[i].def->name, name)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002811 if (ret) {
2812 *ret = ly_types[i].def;
2813 }
2814 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002815 }
2816 }
2817 } else {
Michal Vasko1dca6882015-10-22 14:29:42 +02002818 if (!strcmp(mod_name, module->name)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002819 /* prefix refers to the current module, ignore it */
Michal Vasko1dca6882015-10-22 14:29:42 +02002820 mod_name = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002821 }
2822 }
2823
Michal Vasko1dca6882015-10-22 14:29:42 +02002824 if (!mod_name && parent) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002825 /* search in local typedefs */
2826 while (parent) {
2827 switch (parent->nodetype) {
Radek Krejci76512572015-08-04 09:47:08 +02002828 case LYS_CONTAINER:
Radek Krejcib8048692015-08-05 13:36:34 +02002829 tpdf_size = ((struct lys_node_container *)parent)->tpdf_size;
2830 tpdf = ((struct lys_node_container *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002831 break;
2832
Radek Krejci76512572015-08-04 09:47:08 +02002833 case LYS_LIST:
Radek Krejcib8048692015-08-05 13:36:34 +02002834 tpdf_size = ((struct lys_node_list *)parent)->tpdf_size;
2835 tpdf = ((struct lys_node_list *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002836 break;
2837
Radek Krejci76512572015-08-04 09:47:08 +02002838 case LYS_GROUPING:
Radek Krejcib8048692015-08-05 13:36:34 +02002839 tpdf_size = ((struct lys_node_grp *)parent)->tpdf_size;
2840 tpdf = ((struct lys_node_grp *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002841 break;
2842
Radek Krejci76512572015-08-04 09:47:08 +02002843 case LYS_RPC:
Michal Vasko44fb6382016-06-29 11:12:27 +02002844 case LYS_ACTION:
2845 tpdf_size = ((struct lys_node_rpc_action *)parent)->tpdf_size;
2846 tpdf = ((struct lys_node_rpc_action *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002847 break;
2848
Radek Krejci76512572015-08-04 09:47:08 +02002849 case LYS_NOTIF:
Radek Krejcib8048692015-08-05 13:36:34 +02002850 tpdf_size = ((struct lys_node_notif *)parent)->tpdf_size;
2851 tpdf = ((struct lys_node_notif *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002852 break;
2853
Radek Krejci76512572015-08-04 09:47:08 +02002854 case LYS_INPUT:
2855 case LYS_OUTPUT:
Michal Vasko44fb6382016-06-29 11:12:27 +02002856 tpdf_size = ((struct lys_node_inout *)parent)->tpdf_size;
2857 tpdf = ((struct lys_node_inout *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002858 break;
2859
2860 default:
Michal Vaskodcf98e62016-05-05 17:53:53 +02002861 parent = lys_parent(parent);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002862 continue;
2863 }
2864
2865 for (i = 0; i < tpdf_size; i++) {
Radek Krejcic13db382016-08-16 10:52:42 +02002866 if (!strcmp(tpdf[i].name, name) && tpdf[i].type.base > 0) {
Michal Vasko01c6fd22016-05-20 11:43:05 +02002867 match = &tpdf[i];
2868 goto check_leafref;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002869 }
2870 }
2871
Michal Vaskodcf98e62016-05-05 17:53:53 +02002872 parent = lys_parent(parent);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002873 }
Radek Krejcic071c542016-01-27 14:57:51 +01002874 } else {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002875 /* get module where to search */
Michal Vaskob6729c62015-10-21 12:09:47 +02002876 module = lys_get_import_module(module, NULL, 0, mod_name, 0);
Michal Vaskoc935fff2015-08-17 14:02:06 +02002877 if (!module) {
2878 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002879 }
2880 }
2881
2882 /* search in top level typedefs */
2883 for (i = 0; i < module->tpdf_size; i++) {
Radek Krejcic13db382016-08-16 10:52:42 +02002884 if (!strcmp(module->tpdf[i].name, name) && module->tpdf[i].type.base > 0) {
Michal Vasko01c6fd22016-05-20 11:43:05 +02002885 match = &module->tpdf[i];
2886 goto check_leafref;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002887 }
2888 }
2889
2890 /* search in submodules */
Radek Krejcic071c542016-01-27 14:57:51 +01002891 for (i = 0; i < module->inc_size && module->inc[i].submodule; i++) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002892 for (j = 0; j < module->inc[i].submodule->tpdf_size; j++) {
Radek Krejcic13db382016-08-16 10:52:42 +02002893 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 +02002894 match = &module->inc[i].submodule->tpdf[j];
2895 goto check_leafref;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002896 }
2897 }
2898 }
2899
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002900 return EXIT_FAILURE;
Michal Vasko01c6fd22016-05-20 11:43:05 +02002901
2902check_leafref:
2903 if (ret) {
2904 *ret = match;
2905 }
2906 if (match->type.base == LY_TYPE_LEAFREF) {
2907 while (!match->type.info.lref.path) {
2908 match = match->type.der;
2909 assert(match);
2910 }
Michal Vasko01c6fd22016-05-20 11:43:05 +02002911 }
2912 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002913}
2914
Michal Vasko1dca6882015-10-22 14:29:42 +02002915/**
2916 * @brief Check the default \p value of the \p type. Logs directly.
2917 *
2918 * @param[in] type Type definition to use.
2919 * @param[in] value Default value to check.
Michal Vasko56826402016-03-02 11:11:37 +01002920 * @param[in] module Type module.
Michal Vasko1dca6882015-10-22 14:29:42 +02002921 *
2922 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
2923 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002924static int
Radek Krejci48464ed2016-03-17 15:44:09 +01002925check_default(struct lys_type *type, const char *value, struct lys_module *module)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002926{
Radek Krejcibad2f172016-08-02 11:04:15 +02002927 struct lys_tpdf *base_tpdf = NULL;
Michal Vasko1dca6882015-10-22 14:29:42 +02002928 struct lyd_node_leaf_list node;
Radek Krejci37b756f2016-01-18 10:15:03 +01002929 int ret = EXIT_SUCCESS;
Michal Vasko1dca6882015-10-22 14:29:42 +02002930
Radek Krejcic13db382016-08-16 10:52:42 +02002931 if (type->base <= LY_TYPE_DER) {
Michal Vasko478c4652016-07-21 12:55:01 +02002932 /* the type was not resolved yet, nothing to do for now */
2933 return EXIT_FAILURE;
2934 }
2935
2936 if (!value) {
2937 /* we do not have a new default value, so is there any to check even, in some base type? */
2938 for (base_tpdf = type->der; base_tpdf->type.der; base_tpdf = base_tpdf->type.der) {
2939 if (base_tpdf->dflt) {
2940 value = base_tpdf->dflt;
2941 break;
2942 }
2943 }
2944
2945 if (!value) {
2946 /* no default value, nothing to check, all is well */
2947 return EXIT_SUCCESS;
2948 }
2949
2950 /* 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)? */
2951 switch (type->base) {
Michal Vasko478c4652016-07-21 12:55:01 +02002952 case LY_TYPE_IDENT:
2953 case LY_TYPE_INST:
2954 case LY_TYPE_LEAFREF:
2955 case LY_TYPE_BOOL:
2956 case LY_TYPE_EMPTY:
2957 /* these have no restrictions, so we would do the exact same work as the unres in the base typedef */
2958 return EXIT_SUCCESS;
Radek Krejcibad2f172016-08-02 11:04:15 +02002959 case LY_TYPE_BITS:
2960 /* the default value must match the restricted list of values, if the type was restricted */
2961 if (type->info.bits.count) {
2962 break;
2963 }
2964 return EXIT_SUCCESS;
2965 case LY_TYPE_ENUM:
2966 /* the default value must match the restricted list of values, if the type was restricted */
2967 if (type->info.enums.count) {
2968 break;
2969 }
2970 return EXIT_SUCCESS;
Michal Vasko478c4652016-07-21 12:55:01 +02002971 case LY_TYPE_DEC64:
2972 if (type->info.dec64.range) {
2973 break;
2974 }
2975 return EXIT_SUCCESS;
2976 case LY_TYPE_BINARY:
2977 if (type->info.binary.length) {
2978 break;
2979 }
2980 return EXIT_SUCCESS;
2981 case LY_TYPE_INT8:
2982 case LY_TYPE_INT16:
2983 case LY_TYPE_INT32:
2984 case LY_TYPE_INT64:
2985 case LY_TYPE_UINT8:
2986 case LY_TYPE_UINT16:
2987 case LY_TYPE_UINT32:
2988 case LY_TYPE_UINT64:
2989 if (type->info.num.range) {
2990 break;
2991 }
2992 return EXIT_SUCCESS;
2993 case LY_TYPE_STRING:
2994 if (type->info.str.length || type->info.str.patterns) {
2995 break;
2996 }
2997 return EXIT_SUCCESS;
2998 case LY_TYPE_UNION:
2999 /* way too much trouble learning whether we need to check the default again, so just do it */
3000 break;
3001 default:
3002 LOGINT;
3003 return -1;
3004 }
Radek Krejci55a161c2016-09-05 17:13:25 +02003005 } else if (type->base == LY_TYPE_EMPTY) {
3006 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_NONE, NULL, "default", type->parent->name);
3007 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "The \"empty\" data type cannot have a default value.");
3008 return -1;
Michal Vasko478c4652016-07-21 12:55:01 +02003009 }
3010
Michal Vasko1dca6882015-10-22 14:29:42 +02003011 /* dummy leaf */
Radek Krejci4fe36bd2016-03-17 16:47:16 +01003012 memset(&node, 0, sizeof node);
Michal Vasko1dca6882015-10-22 14:29:42 +02003013 node.value_str = value;
3014 node.value_type = type->base;
Radek Krejci37b756f2016-01-18 10:15:03 +01003015 node.schema = calloc(1, sizeof (struct lys_node_leaf));
Michal Vasko253035f2015-12-17 16:58:13 +01003016 if (!node.schema) {
3017 LOGMEM;
3018 return -1;
3019 }
Radek Krejcibad2f172016-08-02 11:04:15 +02003020 node.schema->name = strdup("fake-default");
Michal Vasko253035f2015-12-17 16:58:13 +01003021 if (!node.schema->name) {
3022 LOGMEM;
Michal Vaskof49eda02016-07-21 12:17:01 +02003023 free(node.schema);
Michal Vasko253035f2015-12-17 16:58:13 +01003024 return -1;
3025 }
Michal Vasko56826402016-03-02 11:11:37 +01003026 node.schema->module = module;
Radek Krejci37b756f2016-01-18 10:15:03 +01003027 memcpy(&((struct lys_node_leaf *)node.schema)->type, type, sizeof *type);
Michal Vasko1dca6882015-10-22 14:29:42 +02003028
Radek Krejci37b756f2016-01-18 10:15:03 +01003029 if (type->base == LY_TYPE_LEAFREF) {
Michal Vasko1dca6882015-10-22 14:29:42 +02003030 if (!type->info.lref.target) {
3031 ret = EXIT_FAILURE;
3032 goto finish;
3033 }
Radek Krejci48464ed2016-03-17 15:44:09 +01003034 ret = check_default(&type->info.lref.target->type, value, module);
Michal Vasko1dca6882015-10-22 14:29:42 +02003035
3036 } else if ((type->base == LY_TYPE_INST) || (type->base == LY_TYPE_IDENT)) {
3037 /* it was converted to JSON format before, nothing else sensible we can do */
3038
3039 } else {
Michal Vasko3767fb22016-07-21 12:10:57 +02003040 if (lyp_parse_value(&node, NULL, 1)) {
3041 ret = -1;
Radek Krejcibad2f172016-08-02 11:04:15 +02003042 if (base_tpdf) {
3043 /* default value was is defined in some base typedef */
3044 if ((type->base == LY_TYPE_BITS && type->der->type.der) ||
3045 (type->base == LY_TYPE_ENUM && type->der->type.der)) {
3046 /* we have refined bits/enums */
3047 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL,
3048 "Invalid value \"%s\" of the default statement inherited to \"%s\" from \"%s\" base type.",
3049 value, type->parent->name, base_tpdf->name);
3050 }
3051 }
Michal Vasko3767fb22016-07-21 12:10:57 +02003052 }
Michal Vasko1dca6882015-10-22 14:29:42 +02003053 }
3054
3055finish:
3056 if (node.value_type == LY_TYPE_BITS) {
3057 free(node.value.bit);
3058 }
3059 free((char *)node.schema->name);
3060 free(node.schema);
3061
3062 return ret;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003063}
3064
Michal Vasko730dfdf2015-08-11 14:48:05 +02003065/**
3066 * @brief Check a key for mandatory attributes. Logs directly.
3067 *
3068 * @param[in] key The key to check.
3069 * @param[in] flags What flags to check.
3070 * @param[in] list The list of all the keys.
3071 * @param[in] index Index of the key in the key list.
3072 * @param[in] name The name of the keys.
3073 * @param[in] len The name length.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003074 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003075 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003076 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003077static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003078check_key(struct lys_node_list *list, int index, const char *name, int len)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003079{
Radek Krejciadb57612016-02-16 13:34:34 +01003080 struct lys_node_leaf *key = list->keys[index];
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003081 char *dup = NULL;
3082 int j;
3083
3084 /* existence */
3085 if (!key) {
Michal Vaskof02e3742015-08-05 16:27:02 +02003086 if (name[len] != '\0') {
3087 dup = strdup(name);
Michal Vasko253035f2015-12-17 16:58:13 +01003088 if (!dup) {
3089 LOGMEM;
3090 return -1;
3091 }
Michal Vaskof02e3742015-08-05 16:27:02 +02003092 dup[len] = '\0';
3093 name = dup;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003094 }
Radek Krejci48464ed2016-03-17 15:44:09 +01003095 LOGVAL(LYE_KEY_MISS, LY_VLOG_LYS, list, name);
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02003096 free(dup);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003097 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003098 }
3099
3100 /* uniqueness */
3101 for (j = index - 1; j >= 0; j--) {
Radek Krejciadb57612016-02-16 13:34:34 +01003102 if (key == list->keys[j]) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003103 LOGVAL(LYE_KEY_DUP, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003104 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003105 }
3106 }
3107
3108 /* key is a leaf */
Radek Krejci76512572015-08-04 09:47:08 +02003109 if (key->nodetype != LYS_LEAF) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003110 LOGVAL(LYE_KEY_NLEAF, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003111 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003112 }
3113
3114 /* type of the leaf is not built-in empty */
Radek Krejcic3738db2016-09-15 15:51:21 +02003115 if (key->type.base == LY_TYPE_EMPTY && key->module->version < 2) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003116 LOGVAL(LYE_KEY_TYPE, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003117 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003118 }
3119
3120 /* config attribute is the same as of the list */
Radek Krejciadb57612016-02-16 13:34:34 +01003121 if ((list->flags & LYS_CONFIG_MASK) != (key->flags & LYS_CONFIG_MASK)) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003122 LOGVAL(LYE_KEY_CONFIG, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003123 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003124 }
3125
Radek Krejci55e2cdc2016-03-11 13:51:09 +01003126 /* key is not placed from augment */
3127 if (key->parent->nodetype == LYS_AUGMENT) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003128 LOGVAL(LYE_KEY_MISS, LY_VLOG_LYS, key, key->name);
3129 LOGVAL(LYE_SPEC, LY_VLOG_LYS, key, "Key inserted from augment.");
Radek Krejci55e2cdc2016-03-11 13:51:09 +01003130 return -1;
3131 }
3132
Radek Krejci3f21ada2016-08-01 13:34:31 +02003133 /* key is not when/if-feature -conditional */
3134 j = 0;
3135 if (key->when || (key->iffeature_size && (j = 1))) {
3136 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, key, j ? "if-feature" : "when", "leaf");
3137 LOGVAL(LYE_SPEC, LY_VLOG_LYS, key, "Key definition cannot depend on a \"%s\" condition.",
3138 j ? "if-feature" : "when");
Radek Krejci581ce772015-11-10 17:22:40 +01003139 return -1;
Michal Vasko730dfdf2015-08-11 14:48:05 +02003140 }
3141
Michal Vasko0b85aa82016-03-07 14:37:43 +01003142 return EXIT_SUCCESS;
Michal Vasko184521f2015-09-24 13:14:26 +02003143}
Michal Vasko730dfdf2015-08-11 14:48:05 +02003144
3145/**
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003146 * @brief Resolve (test the target exists) unique. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003147 *
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003148 * @param[in] parent The parent node of the unique structure.
Michal Vasko0b85aa82016-03-07 14:37:43 +01003149 * @param[in] uniq_str_path One path from the unique string.
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003150 *
3151 * @return EXIT_SUCCESS on succes, EXIT_FAILURE on forward reference, -1 on error.
3152 */
3153int
Radek Krejcid09d1a52016-08-11 14:05:45 +02003154resolve_unique(struct lys_node *parent, const char *uniq_str_path, uint8_t *trg_type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003155{
Radek Krejci581ce772015-11-10 17:22:40 +01003156 int rc;
Michal Vasko1e62a092015-12-01 12:27:20 +01003157 const struct lys_node *leaf = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003158
Radek Krejcif3c71de2016-04-11 12:45:46 +02003159 rc = resolve_descendant_schema_nodeid(uniq_str_path, parent->child, LYS_LEAF, 1, 1, &leaf);
Michal Vasko9bb061b2016-02-12 11:00:19 +01003160 if (rc || !leaf) {
Michal Vasko0b85aa82016-03-07 14:37:43 +01003161 if (rc) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003162 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
Michal Vasko0b85aa82016-03-07 14:37:43 +01003163 if (rc > 0) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003164 LOGVAL(LYE_INCHAR, LY_VLOG_LYS, parent, uniq_str_path[rc - 1], &uniq_str_path[rc - 1]);
Radek Krejcif3c71de2016-04-11 12:45:46 +02003165 } else if (rc == -2) {
Michal Vaskoc66c6d82016-04-12 11:37:31 +02003166 LOGVAL(LYE_SPEC, LY_VLOG_LYS, parent, "Unique argument references list.");
Radek Krejci581ce772015-11-10 17:22:40 +01003167 }
Michal Vasko0b85aa82016-03-07 14:37:43 +01003168 rc = -1;
Michal Vasko0b85aa82016-03-07 14:37:43 +01003169 } else {
Radek Krejci48464ed2016-03-17 15:44:09 +01003170 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
3171 LOGVAL(LYE_SPEC, LY_VLOG_LYS, parent, "Target leaf not found.");
Michal Vasko0b85aa82016-03-07 14:37:43 +01003172 rc = EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003173 }
Radek Krejci581ce772015-11-10 17:22:40 +01003174 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003175 }
Michal Vasko9bb061b2016-02-12 11:00:19 +01003176 if (leaf->nodetype != LYS_LEAF) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003177 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
3178 LOGVAL(LYE_SPEC, LY_VLOG_LYS, parent, "Target is not a leaf.");
Radek Krejcid09d1a52016-08-11 14:05:45 +02003179 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003180 }
3181
Radek Krejcicf509982015-12-15 09:22:44 +01003182 /* check status */
Radek Krejci48464ed2016-03-17 15:44:09 +01003183 if (lyp_check_status(parent->flags, parent->module, parent->name, leaf->flags, leaf->module, leaf->name, leaf)) {
Radek Krejcicf509982015-12-15 09:22:44 +01003184 return -1;
3185 }
3186
Radek Krejcid09d1a52016-08-11 14:05:45 +02003187 /* check that all unique's targets are of the same config type */
3188 if (*trg_type) {
3189 if (((*trg_type == 1) && (leaf->flags & LYS_CONFIG_R)) || ((*trg_type == 2) && (leaf->flags & LYS_CONFIG_W))) {
3190 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
3191 LOGVAL(LYE_SPEC, LY_VLOG_LYS, parent,
3192 "Leaf \"%s\" referenced in unique statement is config %s, but previous referenced leaf is config %s.",
3193 uniq_str_path, *trg_type == 1 ? "false" : "true", *trg_type == 1 ? "true" : "false");
3194 return -1;
3195 }
3196 } else {
3197 /* first unique */
3198 if (leaf->flags & LYS_CONFIG_W) {
3199 *trg_type = 1;
3200 } else {
3201 *trg_type = 2;
3202 }
3203 }
3204
Radek Krejcica7efb72016-01-18 13:06:01 +01003205 /* set leaf's unique flag */
3206 ((struct lys_node_leaf *)leaf)->flags |= LYS_UNIQUE;
3207
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003208 return EXIT_SUCCESS;
3209
3210error:
3211
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003212 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003213}
3214
Radek Krejci0c0086a2016-03-24 15:20:28 +01003215void
Michal Vasko23b61ec2015-08-19 11:19:50 +02003216unres_data_del(struct unres_data *unres, uint32_t i)
3217{
3218 /* there are items after the one deleted */
3219 if (i+1 < unres->count) {
3220 /* we only move the data, memory is left allocated, why bother */
Michal Vaskocf024702015-10-08 15:01:42 +02003221 memmove(&unres->node[i], &unres->node[i+1], (unres->count-(i+1)) * sizeof *unres->node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02003222
3223 /* deleting the last item */
3224 } else if (i == 0) {
Michal Vaskocf024702015-10-08 15:01:42 +02003225 free(unres->node);
3226 unres->node = NULL;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003227 }
3228
3229 /* if there are no items after and it is not the last one, just move the counter */
3230 --unres->count;
3231}
3232
Michal Vasko0491ab32015-08-19 14:28:29 +02003233/**
3234 * @brief Resolve (find) a data node from a specific module. Does not log.
3235 *
3236 * @param[in] mod Module to search in.
3237 * @param[in] name Name of the data node.
3238 * @param[in] nam_len Length of the name.
3239 * @param[in] start Data node to start the search from.
3240 * @param[in,out] parents Resolved nodes. If there are some parents,
3241 * they are replaced (!!) with the resolvents.
3242 *
Michal Vasko2471e7f2016-04-11 11:00:15 +02003243 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko0491ab32015-08-19 14:28:29 +02003244 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003245static int
Michal Vasko1e62a092015-12-01 12:27:20 +01003246resolve_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 +02003247{
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003248 struct lyd_node *node;
Radek Krejcic5090c32015-08-12 09:46:19 +02003249 int flag;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003250 uint32_t i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003251
Michal Vasko23b61ec2015-08-19 11:19:50 +02003252 if (!parents->count) {
3253 parents->count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02003254 parents->node = malloc(sizeof *parents->node);
Michal Vasko253035f2015-12-17 16:58:13 +01003255 if (!parents->node) {
3256 LOGMEM;
Michal Vasko2471e7f2016-04-11 11:00:15 +02003257 return -1;
Michal Vasko253035f2015-12-17 16:58:13 +01003258 }
Michal Vaskocf024702015-10-08 15:01:42 +02003259 parents->node[0] = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003260 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02003261 for (i = 0; i < parents->count;) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02003262 if (parents->node[i] && (parents->node[i]->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003263 /* skip */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003264 ++i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003265 continue;
3266 }
3267 flag = 0;
Michal Vaskocf024702015-10-08 15:01:42 +02003268 LY_TREE_FOR(parents->node[i] ? parents->node[i]->child : start, node) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003269 if (node->schema->module == mod && !strncmp(node->schema->name, name, nam_len)
3270 && node->schema->name[nam_len] == '\0') {
3271 /* matching target */
3272 if (!flag) {
Michal Vasko9a47e122015-09-03 14:26:32 +02003273 /* put node instead of the current parent */
Michal Vaskocf024702015-10-08 15:01:42 +02003274 parents->node[i] = node;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003275 flag = 1;
3276 } else {
Michal Vasko9a47e122015-09-03 14:26:32 +02003277 /* multiple matching, so create a new node */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003278 ++parents->count;
Michal Vasko253035f2015-12-17 16:58:13 +01003279 parents->node = ly_realloc(parents->node, parents->count * sizeof *parents->node);
3280 if (!parents->node) {
3281 return EXIT_FAILURE;
3282 }
Michal Vaskocf024702015-10-08 15:01:42 +02003283 parents->node[parents->count-1] = node;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003284 ++i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003285 }
3286 }
3287 }
Radek Krejcic5090c32015-08-12 09:46:19 +02003288
3289 if (!flag) {
3290 /* remove item from the parents list */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003291 unres_data_del(parents, i);
Radek Krejcic5090c32015-08-12 09:46:19 +02003292 } else {
Michal Vasko23b61ec2015-08-19 11:19:50 +02003293 ++i;
Radek Krejcic5090c32015-08-12 09:46:19 +02003294 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003295 }
3296
Michal Vasko0491ab32015-08-19 14:28:29 +02003297 return parents->count ? EXIT_SUCCESS : EXIT_FAILURE;
Radek Krejcic5090c32015-08-12 09:46:19 +02003298}
3299
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003300/**
3301 * @brief Resolve (find) a data node. Does not log.
3302 *
Radek Krejci581ce772015-11-10 17:22:40 +01003303 * @param[in] mod_name Module name of the data node.
3304 * @param[in] mod_name_len Length of the module name.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003305 * @param[in] name Name of the data node.
3306 * @param[in] nam_len Length of the name.
3307 * @param[in] start Data node to start the search from.
3308 * @param[in,out] parents Resolved nodes. If there are some parents,
3309 * they are replaced (!!) with the resolvents.
3310 *
Michal Vasko0491ab32015-08-19 14:28:29 +02003311 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 otherwise.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003312 */
Radek Krejcic5090c32015-08-12 09:46:19 +02003313static int
Radek Krejci581ce772015-11-10 17:22:40 +01003314resolve_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 +02003315 struct unres_data *parents)
Radek Krejcic5090c32015-08-12 09:46:19 +02003316{
Michal Vasko1e62a092015-12-01 12:27:20 +01003317 const struct lys_module *mod;
Michal Vasko31fc3672015-10-21 12:08:13 +02003318 char *str;
Radek Krejcic5090c32015-08-12 09:46:19 +02003319
Michal Vasko23b61ec2015-08-19 11:19:50 +02003320 assert(start);
3321
Michal Vasko31fc3672015-10-21 12:08:13 +02003322 if (mod_name) {
3323 /* we have mod_name, find appropriate module */
3324 str = strndup(mod_name, mod_name_len);
Michal Vasko253035f2015-12-17 16:58:13 +01003325 if (!str) {
3326 LOGMEM;
3327 return -1;
3328 }
Michal Vasko31fc3672015-10-21 12:08:13 +02003329 mod = ly_ctx_get_module(start->schema->module->ctx, str, NULL);
3330 free(str);
Radek Krejcic5090c32015-08-12 09:46:19 +02003331 if (!mod) {
3332 /* invalid prefix */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003333 return -1;
Radek Krejcic5090c32015-08-12 09:46:19 +02003334 }
3335 } else {
3336 /* no prefix, module is the same as of current node */
3337 mod = start->schema->module;
3338 }
3339
3340 return resolve_data(mod, name, name_len, start, parents);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003341}
3342
Michal Vasko730dfdf2015-08-11 14:48:05 +02003343/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003344 * @brief Resolve a path predicate (leafref) in JSON data context. Logs directly
Radek Krejci48464ed2016-03-17 15:44:09 +01003345 * only specific errors, general no-resolvent error is left to the caller.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003346 *
Michal Vaskobb211122015-08-19 14:03:11 +02003347 * @param[in] pred Predicate to use.
Radek Krejciadb57612016-02-16 13:34:34 +01003348 * @param[in] node Node from which the predicate is being resolved
Michal Vasko730dfdf2015-08-11 14:48:05 +02003349 * @param[in,out] node_match Nodes satisfying the restriction
3350 * without the predicate. Nodes not
3351 * satisfying the predicate are removed.
Michal Vasko0491ab32015-08-19 14:28:29 +02003352 * @param[out] parsed Number of characters parsed, negative on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003353 *
Michal Vasko0491ab32015-08-19 14:28:29 +02003354 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003355 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003356static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003357resolve_path_predicate_data(const char *pred, struct lyd_node *node, struct unres_data *node_match,
Radek Krejci010e54b2016-03-15 09:40:34 +01003358 int *parsed)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003359{
Michal Vasko730dfdf2015-08-11 14:48:05 +02003360 /* ... /node[source = destination] ... */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003361 struct unres_data source_match, dest_match;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003362 const char *path_key_expr, *source, *sour_pref, *dest, *dest_pref;
Michal Vasko0491ab32015-08-19 14:28:29 +02003363 int pke_len, sour_len, sour_pref_len, dest_len, dest_pref_len, parsed_loc = 0, pke_parsed = 0;
3364 int has_predicate, dest_parent_times, i, rc;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003365 uint32_t j;
Radek Krejci0c2fa3a2016-06-13 15:18:03 +02003366 struct lyd_node_leaf_list *leaf_dst, *leaf_src;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003367
3368 source_match.count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02003369 source_match.node = malloc(sizeof *source_match.node);
Michal Vasko253035f2015-12-17 16:58:13 +01003370 if (!source_match.node) {
3371 LOGMEM;
3372 return -1;
3373 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02003374 dest_match.count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02003375 dest_match.node = malloc(sizeof *dest_match.node);
Michal Vasko253035f2015-12-17 16:58:13 +01003376 if (!dest_match.node) {
3377 LOGMEM;
3378 return -1;
3379 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003380
3381 do {
3382 if ((i = parse_path_predicate(pred, &sour_pref, &sour_pref_len, &source, &sour_len, &path_key_expr,
3383 &pke_len, &has_predicate)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003384 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, pred[-i], &pred[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02003385 rc = -1;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003386 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003387 }
Michal Vasko0491ab32015-08-19 14:28:29 +02003388 parsed_loc += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003389 pred += i;
3390
Michal Vasko23b61ec2015-08-19 11:19:50 +02003391 for (j = 0; j < node_match->count;) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003392 /* source */
Michal Vaskocf024702015-10-08 15:01:42 +02003393 source_match.node[0] = node_match->node[j];
Michal Vasko23b61ec2015-08-19 11:19:50 +02003394
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003395 /* must be leaf (key of a list) */
Radek Krejci581ce772015-11-10 17:22:40 +01003396 if ((rc = resolve_data_node(sour_pref, sour_pref_len, source, sour_len, node_match->node[j],
Michal Vaskocf024702015-10-08 15:01:42 +02003397 &source_match)) || (source_match.count != 1) || (source_match.node[0]->schema->nodetype != LYS_LEAF)) {
Michal Vasko23b61ec2015-08-19 11:19:50 +02003398 i = 0;
3399 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003400 }
3401
3402 /* destination */
Radek Krejci0c2fa3a2016-06-13 15:18:03 +02003403 dest_match.node[0] = node;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003404 dest_parent_times = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003405 if ((i = parse_path_key_expr(path_key_expr, &dest_pref, &dest_pref_len, &dest, &dest_len,
3406 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003407 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, path_key_expr[-i], &path_key_expr[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02003408 rc = -1;
3409 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003410 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02003411 pke_parsed = i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003412 for (i = 0; i < dest_parent_times; ++i) {
Michal Vaskocf024702015-10-08 15:01:42 +02003413 dest_match.node[0] = dest_match.node[0]->parent;
3414 if (!dest_match.node[0]) {
Michal Vasko23b61ec2015-08-19 11:19:50 +02003415 i = 0;
Michal Vasko0491ab32015-08-19 14:28:29 +02003416 rc = EXIT_FAILURE;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003417 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003418 }
3419 }
3420 while (1) {
Radek Krejci581ce772015-11-10 17:22:40 +01003421 if ((rc = resolve_data_node(dest_pref, dest_pref_len, dest, dest_len, dest_match.node[0],
Michal Vasko0491ab32015-08-19 14:28:29 +02003422 &dest_match)) || (dest_match.count != 1)) {
Michal Vasko23b61ec2015-08-19 11:19:50 +02003423 i = 0;
3424 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003425 }
3426
3427 if (pke_len == pke_parsed) {
3428 break;
3429 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003430 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 +02003431 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003432 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, path_key_expr[-i], &path_key_expr[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02003433 rc = -1;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003434 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003435 }
3436 pke_parsed += i;
3437 }
3438
3439 /* check match between source and destination nodes */
Radek Krejci0c2fa3a2016-06-13 15:18:03 +02003440 leaf_dst = (struct lyd_node_leaf_list *)dest_match.node[0];
3441 while (leaf_dst->value_type == LY_TYPE_LEAFREF) {
3442 leaf_dst = (struct lyd_node_leaf_list *)leaf_dst->value.leafref;
3443 }
3444 leaf_src = (struct lyd_node_leaf_list *)source_match.node[0];
3445 while (leaf_src->value_type == LY_TYPE_LEAFREF) {
3446 leaf_src = (struct lyd_node_leaf_list *)leaf_src->value.leafref;
3447 }
3448 if (leaf_src->value_type != leaf_dst->value_type) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003449 goto remove_leafref;
3450 }
3451
Radek Krejci0c2fa3a2016-06-13 15:18:03 +02003452 if (!ly_strequal(leaf_src->value_str, leaf_dst->value_str, 1)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003453 goto remove_leafref;
3454 }
3455
3456 /* leafref is ok, continue check with next leafref */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003457 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003458 continue;
3459
3460remove_leafref:
3461 /* does not fulfill conditions, remove leafref record */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003462 unres_data_del(node_match, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003463 }
3464 } while (has_predicate);
3465
Michal Vaskocf024702015-10-08 15:01:42 +02003466 free(source_match.node);
3467 free(dest_match.node);
Michal Vasko0491ab32015-08-19 14:28:29 +02003468 if (parsed) {
3469 *parsed = parsed_loc;
3470 }
3471 return EXIT_SUCCESS;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003472
3473error:
3474
3475 if (source_match.count) {
Michal Vaskocf024702015-10-08 15:01:42 +02003476 free(source_match.node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02003477 }
3478 if (dest_match.count) {
Michal Vaskocf024702015-10-08 15:01:42 +02003479 free(dest_match.node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02003480 }
Michal Vasko0491ab32015-08-19 14:28:29 +02003481 if (parsed) {
3482 *parsed = -parsed_loc+i;
3483 }
3484 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003485}
3486
Michal Vasko730dfdf2015-08-11 14:48:05 +02003487/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003488 * @brief Resolve a path (leafref) in JSON data context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003489 *
Michal Vaskocf024702015-10-08 15:01:42 +02003490 * @param[in] node Leafref data node.
Michal Vasko23b61ec2015-08-19 11:19:50 +02003491 * @param[in] path Path of the leafref.
Radek Krejci48464ed2016-03-17 15:44:09 +01003492 * @param[out] ret Matching nodes. Expects an empty, but allocated structure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003493 *
Michal Vasko0491ab32015-08-19 14:28:29 +02003494 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 otherwise.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003495 */
Michal Vasko184521f2015-09-24 13:14:26 +02003496static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003497resolve_path_arg_data(struct lyd_node *node, const char *path, struct unres_data *ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003498{
Radek Krejci71b795b2015-08-10 16:20:39 +02003499 struct lyd_node *data = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003500 const char *prefix, *name;
Michal Vasko0491ab32015-08-19 14:28:29 +02003501 int pref_len, nam_len, has_predicate, parent_times, i, parsed, rc;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003502 uint32_t j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003503
Michal Vaskocf024702015-10-08 15:01:42 +02003504 assert(node && path && ret && !ret->count);
Michal Vasko23b61ec2015-08-19 11:19:50 +02003505
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003506 parent_times = 0;
Michal Vaskod9173342015-08-17 14:35:36 +02003507 parsed = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003508
3509 /* searching for nodeset */
3510 do {
3511 if ((i = parse_path_arg(path, &prefix, &pref_len, &name, &nam_len, &parent_times, &has_predicate)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003512 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, path[-i], &path[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02003513 rc = -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003514 goto error;
3515 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003516 path += i;
Michal Vaskod9173342015-08-17 14:35:36 +02003517 parsed += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003518
Michal Vasko23b61ec2015-08-19 11:19:50 +02003519 if (!ret->count) {
Michal Vaskobfd98e62016-09-02 09:50:05 +02003520 if (parent_times > 0) {
3521 data = node;
3522 for (i = 1; i < parent_times; ++i) {
3523 data = data->parent;
Michal Vasko253035f2015-12-17 16:58:13 +01003524 }
Michal Vaskobfd98e62016-09-02 09:50:05 +02003525 } else if (!parent_times) {
3526 data = node->child;
3527 } else {
3528 /* absolute path */
3529 for (data = node; data->parent; data = data->parent);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003530 }
3531
Michal Vaskobfd98e62016-09-02 09:50:05 +02003532 /* we may still be parsing it and the pointer is not correct yet */
3533 if (data->prev) {
3534 while (data->prev->next) {
3535 data = data->prev;
Michal Vasko8bcdf292015-08-19 14:04:43 +02003536 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003537 }
3538 }
3539
3540 /* node identifier */
Radek Krejci581ce772015-11-10 17:22:40 +01003541 if ((rc = resolve_data_node(prefix, pref_len, name, nam_len, data, ret))) {
Radek Krejci010e54b2016-03-15 09:40:34 +01003542 if (rc == -1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003543 LOGVAL(LYE_INELEM_LEN, LY_VLOG_LYD, node, nam_len, name);
Michal Vasko184521f2015-09-24 13:14:26 +02003544 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003545 goto error;
3546 }
3547
3548 if (has_predicate) {
3549 /* we have predicate, so the current results must be lists */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003550 for (j = 0; j < ret->count;) {
Michal Vaskocf024702015-10-08 15:01:42 +02003551 if (ret->node[j]->schema->nodetype == LYS_LIST &&
3552 ((struct lys_node_list *)ret->node[0]->schema)->keys) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003553 /* leafref is ok, continue check with next leafref */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003554 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003555 continue;
3556 }
3557
3558 /* does not fulfill conditions, remove leafref record */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003559 unres_data_del(ret, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003560 }
Radek Krejci48464ed2016-03-17 15:44:09 +01003561 if ((rc = resolve_path_predicate_data(path, node, ret, &i))) {
Radek Krejci010e54b2016-03-15 09:40:34 +01003562 if (rc == -1) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003563 LOGVAL(LYE_NORESOLV, LY_VLOG_LYD, node, "leafref", path);
Michal Vasko184521f2015-09-24 13:14:26 +02003564 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003565 goto error;
3566 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003567 path += i;
Michal Vaskod9173342015-08-17 14:35:36 +02003568 parsed += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003569
Michal Vasko23b61ec2015-08-19 11:19:50 +02003570 if (!ret->count) {
Michal Vasko0491ab32015-08-19 14:28:29 +02003571 rc = EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003572 goto error;
3573 }
3574 }
3575 } while (path[0] != '\0');
3576
Michal Vaskof02e3742015-08-05 16:27:02 +02003577 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003578
3579error:
3580
Michal Vaskocf024702015-10-08 15:01:42 +02003581 free(ret->node);
3582 ret->node = NULL;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003583 ret->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003584
Michal Vasko0491ab32015-08-19 14:28:29 +02003585 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003586}
3587
Michal Vaskoe27516a2016-10-10 17:55:31 +00003588static int
3589resolve_path_arg_schema_valid_dep_flag(const struct lys_node *op_node, const struct lys_node *first_node, int abs_path)
3590{
3591 int dep1, dep2;
3592 const struct lys_node *node;
3593
3594 if (lys_parent(op_node)) {
3595 /* inner operation (notif/action) */
3596 if (abs_path) {
3597 return 1;
3598 } else {
3599 /* compare depth of both nodes */
3600 for (dep1 = 0, node = op_node; lys_parent(node); node = lys_parent(node));
3601 for (dep2 = 0, node = first_node; lys_parent(node); node = lys_parent(node));
3602 if ((dep2 > dep1) || ((dep2 == dep1) && (op_node != first_node))) {
3603 return 1;
3604 }
3605 }
3606 } else {
3607 /* top-level operation (notif/rpc) */
3608 if (op_node != first_node) {
3609 return 1;
3610 }
3611 }
3612
3613 return 0;
3614}
3615
Michal Vasko730dfdf2015-08-11 14:48:05 +02003616/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003617 * @brief Resolve a path (leafref) predicate in JSON schema context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003618 *
Michal Vaskobb211122015-08-19 14:03:11 +02003619 * @param[in] path Path to use.
Radek Krejciadb57612016-02-16 13:34:34 +01003620 * @param[in] context_node Predicate context node (where the predicate is placed).
3621 * @param[in] parent Path context node (where the path begins/is placed).
Michal Vaskoe27516a2016-10-10 17:55:31 +00003622 * @param[in] op_node Optional node if the leafref is in an operation (action/rpc/notif).
Michal Vasko730dfdf2015-08-11 14:48:05 +02003623 *
Michal Vasko184521f2015-09-24 13:14:26 +02003624 * @return 0 on forward reference, otherwise the number
3625 * of characters successfully parsed,
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003626 * positive on success, negative on failure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003627 */
Michal Vasko1f76a282015-08-04 16:16:53 +02003628static int
Radek Krejciadb57612016-02-16 13:34:34 +01003629resolve_path_predicate_schema(const char *path, const struct lys_node *context_node,
Michal Vaskoe27516a2016-10-10 17:55:31 +00003630 struct lys_node *parent, const struct lys_node *op_node)
Michal Vasko1f76a282015-08-04 16:16:53 +02003631{
Michal Vasko1e62a092015-12-01 12:27:20 +01003632 const struct lys_node *src_node, *dst_node;
Michal Vasko1f76a282015-08-04 16:16:53 +02003633 const char *path_key_expr, *source, *sour_pref, *dest, *dest_pref;
3634 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 +00003635 int has_predicate, dest_parent_times = 0, i, rc, first_iter;
Michal Vasko1f76a282015-08-04 16:16:53 +02003636
3637 do {
Michal Vasko730dfdf2015-08-11 14:48:05 +02003638 if ((i = parse_path_predicate(path, &sour_pref, &sour_pref_len, &source, &sour_len, &path_key_expr,
Michal Vasko1f76a282015-08-04 16:16:53 +02003639 &pke_len, &has_predicate)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003640 LOGVAL(LYE_INCHAR, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, path[-i], path-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02003641 return -parsed+i;
3642 }
3643 parsed += i;
Michal Vasko730dfdf2015-08-11 14:48:05 +02003644 path += i;
Michal Vasko1f76a282015-08-04 16:16:53 +02003645
Michal Vasko58090902015-08-13 14:04:15 +02003646 /* source (must be leaf) */
Michal Vasko36cbaa42015-12-14 13:15:48 +01003647 if (!sour_pref) {
Radek Krejciadb57612016-02-16 13:34:34 +01003648 sour_pref = context_node->module->name;
Michal Vasko36cbaa42015-12-14 13:15:48 +01003649 }
Radek Krejciadb57612016-02-16 13:34:34 +01003650 rc = lys_get_sibling(context_node->child, sour_pref, sour_pref_len, source, sour_len,
Michal Vasko59ad4582016-09-16 13:15:41 +02003651 LYS_LEAF | LYS_LEAFLIST | LYS_AUGMENT, &src_node);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003652 if (rc) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003653 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path-parsed);
Michal Vasko184521f2015-09-24 13:14:26 +02003654 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003655 }
3656
3657 /* destination */
3658 if ((i = parse_path_key_expr(path_key_expr, &dest_pref, &dest_pref_len, &dest, &dest_len,
3659 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003660 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 +02003661 return -parsed;
3662 }
3663 pke_parsed += i;
3664
Radek Krejciadb57612016-02-16 13:34:34 +01003665 for (i = 0, dst_node = parent; i < dest_parent_times; ++i) {
Michal Vaskofbaead72016-10-07 10:54:48 +02003666 /* path is supposed to be evaluated in data tree, so we have to skip
3667 * all schema nodes that cannot be instantiated in data tree */
3668 for (dst_node = lys_parent(dst_node);
Michal Vaskoe27516a2016-10-10 17:55:31 +00003669 dst_node && !(dst_node->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_ACTION | LYS_NOTIF | LYS_RPC));
Michal Vaskofbaead72016-10-07 10:54:48 +02003670 dst_node = lys_parent(dst_node));
3671
Michal Vasko1f76a282015-08-04 16:16:53 +02003672 if (!dst_node) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003673 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path_key_expr);
Michal Vasko184521f2015-09-24 13:14:26 +02003674 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003675 }
3676 }
Michal Vaskoe27516a2016-10-10 17:55:31 +00003677 first_iter = 1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003678 while (1) {
Michal Vasko36cbaa42015-12-14 13:15:48 +01003679 if (!dest_pref) {
3680 dest_pref = dst_node->module->name;
3681 }
3682 rc = lys_get_sibling(dst_node->child, dest_pref, dest_pref_len, dest, dest_len,
Michal Vasko165dc4a2015-10-23 09:44:27 +02003683 LYS_CONTAINER | LYS_LIST | LYS_LEAF | LYS_AUGMENT, &dst_node);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003684 if (rc) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003685 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path_key_expr);
Michal Vasko184521f2015-09-24 13:14:26 +02003686 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003687 }
3688
Michal Vaskoe27516a2016-10-10 17:55:31 +00003689 if (first_iter) {
3690 if (resolve_path_arg_schema_valid_dep_flag(op_node, dst_node, 0)) {
3691 parent->flags |= LYS_VALID_DEP;
3692 }
3693 first_iter = 0;
3694 }
3695
Michal Vasko1f76a282015-08-04 16:16:53 +02003696 if (pke_len == pke_parsed) {
3697 break;
3698 }
3699
3700 if ((i = parse_path_key_expr(path_key_expr+pke_parsed, &dest_pref, &dest_pref_len, &dest, &dest_len,
3701 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003702 LOGVAL(LYE_INCHAR, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent,
Radek Krejciadb57612016-02-16 13:34:34 +01003703 (path_key_expr+pke_parsed)[-i], (path_key_expr+pke_parsed)-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02003704 return -parsed;
3705 }
3706 pke_parsed += i;
3707 }
3708
3709 /* check source - dest match */
Michal Vasko59ad4582016-09-16 13:15:41 +02003710 if (dst_node->nodetype != src_node->nodetype) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003711 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path-parsed);
Michal Vasko59ad4582016-09-16 13:15:41 +02003712 LOGVAL(LYE_SPEC, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "Destination node is not a %s, but a %s.",
3713 strnodetype(src_node->nodetype), strnodetype(dst_node->nodetype));
Michal Vasko184521f2015-09-24 13:14:26 +02003714 return -parsed;
3715 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003716 } while (has_predicate);
3717
3718 return parsed;
3719}
3720
Michal Vasko730dfdf2015-08-11 14:48:05 +02003721/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003722 * @brief Resolve a path (leafref) in JSON schema context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003723 *
Michal Vaskobb211122015-08-19 14:03:11 +02003724 * @param[in] path Path to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003725 * @param[in] parent_node Parent of the leafref.
Radek Krejci2f12f852016-01-08 12:59:57 +01003726 * @param[in] parent_tpdf Flag if the parent node is actually typedef, in that case the path
3727 * has to contain absolute path
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003728 * @param[out] ret Pointer to the resolved schema node. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003729 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003730 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003731 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003732static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003733resolve_path_arg_schema(const char *path, struct lys_node *parent, int parent_tpdf,
Michal Vasko36cbaa42015-12-14 13:15:48 +01003734 const struct lys_node **ret)
Michal Vasko1f76a282015-08-04 16:16:53 +02003735{
Michal Vaskoe27516a2016-10-10 17:55:31 +00003736 const struct lys_node *node, *op_node = NULL;
Radek Krejci27fe55e2016-09-13 17:13:35 +02003737 const struct lys_module *mod, *mod2;
Michal Vasko1f76a282015-08-04 16:16:53 +02003738 const char *id, *prefix, *name;
3739 int pref_len, nam_len, parent_times, has_predicate;
Michal Vaskoe27516a2016-10-10 17:55:31 +00003740 int i, first_iter, rc;
Michal Vasko1f76a282015-08-04 16:16:53 +02003741
Michal Vasko184521f2015-09-24 13:14:26 +02003742 first_iter = 1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003743 parent_times = 0;
3744 id = path;
3745
Michal Vaskoe27516a2016-10-10 17:55:31 +00003746 /* find operation schema we are in, if applicable */
Michal Vaskoe9914d12016-10-07 14:32:37 +02003747 if (!parent_tpdf) {
Michal Vaskoe27516a2016-10-10 17:55:31 +00003748 for (op_node = lys_parent(parent);
3749 op_node && !(op_node->nodetype & (LYS_ACTION | LYS_NOTIF | LYS_RPC));
3750 op_node = lys_parent(op_node));
Michal Vaskoe9914d12016-10-07 14:32:37 +02003751 }
3752
Radek Krejci27fe55e2016-09-13 17:13:35 +02003753 mod2 = lys_node_module(parent);
Michal Vasko1f76a282015-08-04 16:16:53 +02003754 do {
3755 if ((i = parse_path_arg(id, &prefix, &pref_len, &name, &nam_len, &parent_times, &has_predicate)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003756 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 +02003757 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003758 }
3759 id += i;
3760
Michal Vasko184521f2015-09-24 13:14:26 +02003761 if (first_iter) {
Michal Vasko1f76a282015-08-04 16:16:53 +02003762 if (parent_times == -1) {
Radek Krejcic071c542016-01-27 14:57:51 +01003763 /* resolve prefix of the module */
Radek Krejciadb57612016-02-16 13:34:34 +01003764 mod = lys_get_import_module(parent->module, NULL, 0, prefix, pref_len);
Radek Krejci0fa54e92016-09-14 14:01:05 +02003765 mod = lys_get_implemented_module(mod);
Radek Krejcic071c542016-01-27 14:57:51 +01003766 /* get start node */
3767 node = mod ? mod->data : NULL;
Michal Vasko58090902015-08-13 14:04:15 +02003768 if (!node) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003769 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent,
3770 "leafref", path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003771 return EXIT_FAILURE;
Michal Vasko58090902015-08-13 14:04:15 +02003772 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003773 } else if (parent_times > 0) {
Radek Krejci2f12f852016-01-08 12:59:57 +01003774 if (parent_tpdf) {
3775 /* the path is not allowed to contain relative path since we are in top level typedef */
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003776 LOGVAL(LYE_NORESOLV, 0, NULL, "leafref", path);
Radek Krejci2f12f852016-01-08 12:59:57 +01003777 return -1;
3778 }
3779
Michal Vasko94458082016-10-07 14:34:36 +02003780 /* we are looking for a sibling of a node, node it's parent (that is why parent_times - 1) */
3781 for (i = 0, node = parent; i < parent_times - 1; i++) {
Radek Krejci3a5501d2016-07-18 22:03:34 +02003782 /* path is supposed to be evaluated in data tree, so we have to skip
3783 * all schema nodes that cannot be instantiated in data tree */
3784 for (node = lys_parent(node);
Michal Vaskoe27516a2016-10-10 17:55:31 +00003785 node && !(node->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_ACTION | LYS_NOTIF | LYS_RPC));
Radek Krejci3a5501d2016-07-18 22:03:34 +02003786 node = lys_parent(node));
3787
Michal Vasko1f76a282015-08-04 16:16:53 +02003788 if (!node) {
Michal Vaskoe9914d12016-10-07 14:32:37 +02003789 LOGVAL(LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003790 return EXIT_FAILURE;
Michal Vasko1f76a282015-08-04 16:16:53 +02003791 }
3792 }
Michal Vaskoe01eca52015-08-13 14:42:02 +02003793 } else {
3794 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003795 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003796 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003797 } else {
Michal Vasko7dc71d02016-03-15 10:42:28 +01003798 /* move down the tree, if possible */
Radek Krejcibf2abff2016-08-23 15:51:52 +02003799 if (node->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
Michal Vasko2f5aceb2016-03-22 10:24:14 +01003800 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 +01003801 return -1;
3802 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003803 node = node->child;
Radek Krejci6892c272016-10-18 20:40:06 +02003804 if (!node) {
3805 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent,
3806 "leafref", path);
3807 return EXIT_FAILURE;
3808 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003809 }
3810
Michal Vasko4f0dad02016-02-15 14:08:23 +01003811 if (!prefix) {
Radek Krejciadb57612016-02-16 13:34:34 +01003812 prefix = lys_node_module(parent)->name;
Michal Vasko4f0dad02016-02-15 14:08:23 +01003813 }
3814
Michal Vasko36cbaa42015-12-14 13:15:48 +01003815 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 +02003816 if (rc) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003817 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent, "leafref", path);
Michal Vasko7a55bea2016-05-02 14:51:20 +02003818 return EXIT_FAILURE;
Michal Vasko1f76a282015-08-04 16:16:53 +02003819 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003820
Michal Vaskoe27516a2016-10-10 17:55:31 +00003821 if (first_iter) {
3822 /* set external dependency flag, we can decide based on the first found node */
3823 if (!parent_tpdf && op_node && parent_times &&
3824 resolve_path_arg_schema_valid_dep_flag(op_node, node, (parent_times == -1 ? 1 : 0))) {
3825 parent->flags |= LYS_VALID_DEP;
3826 }
3827 first_iter = 0;
3828 }
3829
Michal Vasko1f76a282015-08-04 16:16:53 +02003830 if (has_predicate) {
3831 /* we have predicate, so the current result must be list */
3832 if (node->nodetype != LYS_LIST) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003833 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent, "leafref", path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003834 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003835 }
3836
Michal Vaskoe27516a2016-10-10 17:55:31 +00003837 i = resolve_path_predicate_schema(id, node, parent, op_node);
Radek Krejci27fe55e2016-09-13 17:13:35 +02003838 if (i <= 0) {
3839 if (i == 0) {
3840 return EXIT_FAILURE;
3841 } else { /* i < 0 */
3842 return -1;
3843 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003844 }
3845 id += i;
3846 }
Radek Krejci27fe55e2016-09-13 17:13:35 +02003847 mod = lys_node_module(node);
3848 if (!mod->implemented && mod != mod2) {
3849 /* set the module implemented */
3850 if (lys_set_implemented(mod)) {
3851 return -1;
3852 }
3853 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003854 } while (id[0]);
3855
Michal Vaskoca917682016-07-25 11:00:37 +02003856 /* the target must be leaf or leaf-list (in YANG 1.1 only) */
3857 if ((node->nodetype != LYS_LEAF) && ((lys_node_module(parent)->version != 2) || (node->nodetype != LYS_LEAFLIST))) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003858 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent, "leafref", path);
Radek Krejcid47daf62016-08-22 16:23:38 +02003859 LOGVAL(LYE_SPEC, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent,
3860 "Leafref target \"%s\" is not a leaf%s.", path,
3861 lys_node_module(parent)->version != 2 ? "" : " nor a leaf-list");
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003862 return -1;
Radek Krejcib1c12512015-08-11 11:22:04 +02003863 }
3864
Radek Krejcicf509982015-12-15 09:22:44 +01003865 /* check status */
Radek Krejciadb57612016-02-16 13:34:34 +01003866 if (lyp_check_status(parent->flags, parent->module, parent->name,
Radek Krejci48464ed2016-03-17 15:44:09 +01003867 node->flags, node->module, node->name, node)) {
Radek Krejcicf509982015-12-15 09:22:44 +01003868 return -1;
3869 }
3870
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003871 if (ret) {
3872 *ret = node;
3873 }
Radek Krejci27fe55e2016-09-13 17:13:35 +02003874
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003875 return EXIT_SUCCESS;
Michal Vasko1f76a282015-08-04 16:16:53 +02003876}
3877
Michal Vasko730dfdf2015-08-11 14:48:05 +02003878/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003879 * @brief Resolve instance-identifier predicate in JSON data format.
3880 * Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003881 *
Michal Vaskobb211122015-08-19 14:03:11 +02003882 * @param[in] pred Predicate to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003883 * @param[in,out] node_match Nodes matching the restriction without
3884 * the predicate. Nodes not satisfying
3885 * the predicate are removed.
3886 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003887 * @return Number of characters successfully parsed,
3888 * positive on success, negative on failure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003889 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003890static int
Michal Vaskof39142b2015-10-21 11:40:05 +02003891resolve_predicate(const char *pred, struct unres_data *node_match)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003892{
Michal Vasko730dfdf2015-08-11 14:48:05 +02003893 /* ... /node[target = value] ... */
Michal Vaskob2f40be2016-09-08 16:03:48 +02003894 struct lyd_node *target;
Michal Vasko1f2cc332015-08-19 11:18:32 +02003895 const char *model, *name, *value;
Michal Vaskob2f40be2016-09-08 16:03:48 +02003896 int mod_len, nam_len, val_len, i, has_predicate, cur_idx, idx, parsed, pred_iter, k;
Michal Vasko1f2cc332015-08-19 11:18:32 +02003897 uint32_t j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003898
Michal Vasko1f2cc332015-08-19 11:18:32 +02003899 assert(pred && node_match->count);
3900
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003901 idx = -1;
3902 parsed = 0;
3903
Michal Vaskob2f40be2016-09-08 16:03:48 +02003904 pred_iter = -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003905 do {
Michal Vaskof39142b2015-10-21 11:40:05 +02003906 if ((i = parse_predicate(pred, &model, &mod_len, &name, &nam_len, &value, &val_len, &has_predicate)) < 1) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003907 return -parsed+i;
3908 }
3909 parsed += i;
3910 pred += i;
3911
3912 if (isdigit(name[0])) {
Michal Vaskob2f40be2016-09-08 16:03:48 +02003913 /* pos */
3914 assert(!value);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003915 idx = atoi(name);
Michal Vaskob2f40be2016-09-08 16:03:48 +02003916 } else if (name[0] != '.') {
3917 /* list keys */
3918 if (pred_iter < 0) {
3919 pred_iter = 1;
3920 } else {
3921 ++pred_iter;
3922 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003923 }
3924
Michal Vaskof2f28a12016-09-09 12:43:06 +02003925 for (cur_idx = 1, j = 0; j < node_match->count; ++cur_idx) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003926 /* target */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003927 if (name[0] == '.') {
Michal Vaskob2f40be2016-09-08 16:03:48 +02003928 /* leaf-list value */
Michal Vaskocf024702015-10-08 15:01:42 +02003929 if (node_match->node[j]->schema->nodetype != LYS_LEAFLIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003930 goto remove_instid;
3931 }
Michal Vaskob2f40be2016-09-08 16:03:48 +02003932
3933 target = node_match->node[j];
3934 /* check the value */
3935 if (strncmp(((struct lyd_node_leaf_list *)target)->value_str, value, val_len)
3936 || ((struct lyd_node_leaf_list *)target)->value_str[val_len]) {
3937 goto remove_instid;
3938 }
3939
3940 } else if (!value) {
3941 /* keyless list position */
3942 if ((node_match->node[j]->schema->nodetype != LYS_LIST)
3943 || ((struct lys_node_list *)node_match->node[j]->schema)->keys) {
3944 goto remove_instid;
3945 }
3946
3947 if (idx != cur_idx) {
3948 goto remove_instid;
3949 }
3950
3951 } else {
3952 /* list key value */
Michal Vaskocf024702015-10-08 15:01:42 +02003953 if (node_match->node[j]->schema->nodetype != LYS_LIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003954 goto remove_instid;
3955 }
Michal Vaskob2f40be2016-09-08 16:03:48 +02003956
3957 /* key module must match the list module */
3958 if (strncmp(node_match->node[j]->schema->module->name, model, mod_len)
3959 || node_match->node[j]->schema->module->name[mod_len]) {
3960 goto remove_instid;
3961 }
3962 /* find the key leaf */
Michal Vasko045182c2016-09-09 12:44:07 +02003963 for (k = 1, target = node_match->node[j]->child; target && (k < pred_iter); k++, target = target->next);
Michal Vaskob2f40be2016-09-08 16:03:48 +02003964 if (!target) {
3965 goto remove_instid;
3966 }
3967 if ((struct lys_node_leaf *)target->schema !=
3968 ((struct lys_node_list *)node_match->node[j]->schema)->keys[pred_iter - 1]) {
3969 goto remove_instid;
3970 }
3971
3972 /* check the value */
3973 if (strncmp(((struct lyd_node_leaf_list *)target)->value_str, value, val_len)
3974 || ((struct lyd_node_leaf_list *)target)->value_str[val_len]) {
3975 goto remove_instid;
3976 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003977 }
3978
Michal Vaskob2f40be2016-09-08 16:03:48 +02003979 /* instid is ok, continue check with the next one */
Michal Vasko1f2cc332015-08-19 11:18:32 +02003980 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003981 continue;
3982
3983remove_instid:
Michal Vaskob2f40be2016-09-08 16:03:48 +02003984 /* does not fulfill conditions, remove instid record */
Michal Vasko1f2cc332015-08-19 11:18:32 +02003985 unres_data_del(node_match, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003986 }
3987 } while (has_predicate);
3988
Michal Vaskob2f40be2016-09-08 16:03:48 +02003989 /* check that all list keys were specified */
3990 if ((pred_iter > 0) && node_match->count) {
Michal Vasko045182c2016-09-09 12:44:07 +02003991 j = 0;
3992 while (j < node_match->count) {
Michal Vaskob2f40be2016-09-08 16:03:48 +02003993 assert(node_match->node[j]->schema->nodetype == LYS_LIST);
3994 if (pred_iter < ((struct lys_node_list *)node_match->node[j]->schema)->keys_size) {
3995 /* not enough predicates, just remove the list instance */
3996 unres_data_del(node_match, j);
Michal Vasko045182c2016-09-09 12:44:07 +02003997 } else {
3998 ++j;
Michal Vaskob2f40be2016-09-08 16:03:48 +02003999 }
4000 }
4001
4002 if (!node_match->count) {
4003 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Instance identifier is missing some list keys.");
4004 }
4005 }
4006
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004007 return parsed;
4008}
4009
Michal Vasko730dfdf2015-08-11 14:48:05 +02004010/**
Michal Vaskof39142b2015-10-21 11:40:05 +02004011 * @brief Resolve instance-identifier in JSON data format. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004012 *
Radek Krejciadb57612016-02-16 13:34:34 +01004013 * @param[in] data Data node where the path is used
Michal Vasko730dfdf2015-08-11 14:48:05 +02004014 * @param[in] path Instance-identifier node value.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004015 *
Radek Krejcic5090c32015-08-12 09:46:19 +02004016 * @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 +02004017 */
Michal Vasko184521f2015-09-24 13:14:26 +02004018static struct lyd_node *
Radek Krejci48464ed2016-03-17 15:44:09 +01004019resolve_instid(struct lyd_node *data, const char *path)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004020{
Radek Krejcic5090c32015-08-12 09:46:19 +02004021 int i = 0, j;
4022 struct lyd_node *result = NULL;
Michal Vaskob2f40be2016-09-08 16:03:48 +02004023 const struct lys_module *mod;
Radek Krejcic5090c32015-08-12 09:46:19 +02004024 struct ly_ctx *ctx = data->schema->module->ctx;
Michal Vasko1f2cc332015-08-19 11:18:32 +02004025 const char *model, *name;
Radek Krejcic5090c32015-08-12 09:46:19 +02004026 char *str;
Michal Vasko1f2cc332015-08-19 11:18:32 +02004027 int mod_len, name_len, has_predicate;
4028 struct unres_data node_match;
Michal Vasko1f2cc332015-08-19 11:18:32 +02004029
4030 memset(&node_match, 0, sizeof node_match);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004031
Radek Krejcic5090c32015-08-12 09:46:19 +02004032 /* we need root to resolve absolute path */
4033 for (; data->parent; data = data->parent);
Michal Vaskodb9323c2015-10-16 10:32:44 +02004034 /* we're still parsing it and the pointer is not correct yet */
Michal Vasko0491ab32015-08-19 14:28:29 +02004035 if (data->prev) {
4036 for (; data->prev->next; data = data->prev);
4037 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004038
Radek Krejcic5090c32015-08-12 09:46:19 +02004039 /* search for the instance node */
4040 while (path[i]) {
Michal Vaskof39142b2015-10-21 11:40:05 +02004041 j = parse_instance_identifier(&path[i], &model, &mod_len, &name, &name_len, &has_predicate);
Radek Krejcic5090c32015-08-12 09:46:19 +02004042 if (j <= 0) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004043 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, data, path[i-j], &path[i-j]);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004044 goto error;
4045 }
Radek Krejcic5090c32015-08-12 09:46:19 +02004046 i += j;
Michal Vaskob387c482015-08-12 09:32:59 +02004047
Michal Vaskob2f40be2016-09-08 16:03:48 +02004048 str = strndup(model, mod_len);
4049 if (!str) {
4050 LOGMEM;
4051 goto error;
Radek Krejcic5090c32015-08-12 09:46:19 +02004052 }
Michal Vaskob2f40be2016-09-08 16:03:48 +02004053 mod = ly_ctx_get_module(ctx, str, NULL);
4054 free(str);
Radek Krejcic5090c32015-08-12 09:46:19 +02004055
Michal Vasko1f2cc332015-08-19 11:18:32 +02004056 if (resolve_data(mod, name, name_len, data, &node_match)) {
Radek Krejcic5090c32015-08-12 09:46:19 +02004057 /* no instance exists */
4058 return NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004059 }
4060
4061 if (has_predicate) {
4062 /* we have predicate, so the current results must be list or leaf-list */
Michal Vaskof39142b2015-10-21 11:40:05 +02004063 j = resolve_predicate(&path[i], &node_match);
Radek Krejcic5090c32015-08-12 09:46:19 +02004064 if (j < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004065 LOGVAL(LYE_INPRED, LY_VLOG_LYD, data, &path[i-j]);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004066 goto error;
4067 }
Michal Vasko1f2cc332015-08-19 11:18:32 +02004068 i += j;
Michal Vaskob387c482015-08-12 09:32:59 +02004069
Michal Vasko1f2cc332015-08-19 11:18:32 +02004070 if (!node_match.count) {
Radek Krejcic5090c32015-08-12 09:46:19 +02004071 /* no instance exists */
4072 return NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004073 }
4074 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004075 }
4076
Michal Vasko1f2cc332015-08-19 11:18:32 +02004077 if (!node_match.count) {
Radek Krejcic5090c32015-08-12 09:46:19 +02004078 /* no instance exists */
4079 return NULL;
Michal Vasko23b61ec2015-08-19 11:19:50 +02004080 } else if (node_match.count > 1) {
Radek Krejcic5090c32015-08-12 09:46:19 +02004081 /* instance identifier must resolve to a single node */
Radek Krejci48464ed2016-03-17 15:44:09 +01004082 LOGVAL(LYE_TOOMANY, LY_VLOG_LYD, data, path, "data tree");
Michal Vaskod6adbaa2016-04-11 11:01:09 +02004083 goto error;
Radek Krejcic5090c32015-08-12 09:46:19 +02004084 } else {
4085 /* we have required result, remember it and cleanup */
Michal Vaskocf024702015-10-08 15:01:42 +02004086 result = node_match.node[0];
4087 free(node_match.node);
Radek Krejcic5090c32015-08-12 09:46:19 +02004088 return result;
4089 }
4090
4091error:
Radek Krejcic5090c32015-08-12 09:46:19 +02004092 /* cleanup */
Michal Vaskocf024702015-10-08 15:01:42 +02004093 free(node_match.node);
Radek Krejcic5090c32015-08-12 09:46:19 +02004094 return NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004095}
4096
Michal Vasko730dfdf2015-08-11 14:48:05 +02004097/**
Michal Vasko9e635ac2016-10-17 11:44:09 +02004098 * @brief Check all XPath expressions of a node (when and must), set LYS_XPATH_DEP flag if required.
4099 *
4100 * @param[in] node Node to examine.
4101 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
4102 */
4103static int
4104check_node_xpath(struct lys_node *node)
4105{
4106 struct lys_node *parent, *elem;
4107 struct lyxp_set set;
4108 uint32_t i;
4109 int rc;
4110
4111 parent = node;
4112 while (parent) {
4113 if (parent->nodetype == LYS_GROUPING) {
4114 /* unresolved grouping, skip for now (will be checked later) */
4115 return EXIT_SUCCESS;
4116 }
4117 if (parent->nodetype == LYS_AUGMENT) {
4118 if (!((struct lys_node_augment *)parent)->target) {
4119 /* uresolved augment, skip for now (will be checked later) */
4120 return EXIT_SUCCESS;
4121 } else {
4122 parent = ((struct lys_node_augment *)parent)->target;
4123 continue;
4124 }
4125 }
4126 parent = parent->parent;
4127 }
4128
4129 rc = lyxp_node_atomize(node, &set);
4130 if (rc) {
4131 return rc;
4132 }
4133
4134 for (parent = node; parent && !(parent->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)); parent = lys_parent(parent));
4135
4136 for (i = 0; i < set.used; ++i) {
4137 /* skip roots'n'stuff */
4138 if (set.val.snodes[i].type == LYXP_NODE_ELEM) {
4139 /* XPath expression cannot reference "lower" status than the node that has the definition */
4140 if (lyp_check_status(node->flags, lys_node_module(node), node->name, set.val.snodes[i].snode->flags,
4141 lys_node_module(set.val.snodes[i].snode), set.val.snodes[i].snode->name, node)) {
4142 return -1;
4143 }
4144
4145 if (parent) {
4146 for (elem = set.val.snodes[i].snode; elem && (elem != parent); elem = lys_parent(elem));
4147 if (!elem) {
4148 /* not in node's RPC or notification subtree, set the flag */
4149 node->flags |= LYS_VALID_DEP;
4150 break;
4151 }
4152 }
4153 }
4154 }
4155
4156 free(set.val.snodes);
4157 return EXIT_SUCCESS;
4158}
4159
4160/**
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004161 * @brief Passes config flag down to children, skips nodes without config flags.
4162 * Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004163 *
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004164 * @param[in] node Siblings and their children to have flags changed.
Michal Vaskoe022a562016-09-27 14:24:15 +02004165 * @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 +02004166 * @param[in] flags Flags to assign to all the nodes.
Michal Vaskoa86508c2016-08-26 14:30:19 +02004167 *
4168 * @return 0 on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004169 */
Michal Vaskoa86508c2016-08-26 14:30:19 +02004170static int
Michal Vasko9e635ac2016-10-17 11:44:09 +02004171inherit_config_flag(struct lys_node *node, int flags, int clear, int check_list, int check_xpath)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004172{
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004173 assert(!(flags ^ (flags & LYS_CONFIG_MASK)));
Radek Krejci1d82ef62015-08-07 14:44:40 +02004174 LY_TREE_FOR(node, node) {
Michal Vasko9e635ac2016-10-17 11:44:09 +02004175 if (check_xpath && check_node_xpath(node)) {
4176 return -1;
4177 }
Michal Vaskoe022a562016-09-27 14:24:15 +02004178 if (clear) {
4179 node->flags &= ~LYS_CONFIG_MASK;
Michal Vaskoc2a8d362016-09-29 08:50:13 +02004180 node->flags &= ~LYS_CONFIG_SET;
Michal Vaskoe022a562016-09-27 14:24:15 +02004181 } else {
4182 if (node->flags & LYS_CONFIG_SET) {
4183 /* skip nodes with an explicit config value */
4184 if ((flags & LYS_CONFIG_R) && (node->flags & LYS_CONFIG_W)) {
4185 LOGVAL(LYE_INARG, LY_VLOG_LYS, node, "true", "config");
4186 LOGVAL(LYE_SPEC, LY_VLOG_LYS, node, "State nodes cannot have configuration nodes as children.");
4187 return -1;
4188 }
4189 continue;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004190 }
Michal Vaskoe022a562016-09-27 14:24:15 +02004191
4192 if (!(node->nodetype & (LYS_USES | LYS_GROUPING))) {
4193 node->flags = (node->flags & ~LYS_CONFIG_MASK) | flags;
4194 /* check that configuration lists have keys */
4195 if (check_list && (node->nodetype == LYS_LIST)
4196 && (node->flags & LYS_CONFIG_W) && !((struct lys_node_list *)node)->keys_size) {
4197 LOGVAL(LYE_MISSCHILDSTMT, LY_VLOG_LYS, node, "key", "list");
4198 return -1;
4199 }
4200 }
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004201 }
Radek Krejcibf2abff2016-08-23 15:51:52 +02004202 if (!(node->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
Michal Vasko9e635ac2016-10-17 11:44:09 +02004203 if (inherit_config_flag(node->child, flags, clear, check_list, check_xpath)) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004204 return -1;
4205 }
Radek Krejci3a5501d2016-07-18 22:03:34 +02004206 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004207 }
Michal Vaskoa86508c2016-08-26 14:30:19 +02004208
4209 return 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004210}
4211
Michal Vasko730dfdf2015-08-11 14:48:05 +02004212/**
Michal Vasko7178e692016-02-12 15:58:05 +01004213 * @brief Resolve augment target. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004214 *
Michal Vaskobb211122015-08-19 14:03:11 +02004215 * @param[in] aug Augment to use.
Michal Vasko3edeaf72016-02-11 13:17:43 +01004216 * @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 +02004217 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004218 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004219 */
Michal Vasko7178e692016-02-12 15:58:05 +01004220static int
Radek Krejci48464ed2016-03-17 15:44:09 +01004221resolve_augment(struct lys_node_augment *aug, struct lys_node *siblings)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004222{
Michal Vaskoe022a562016-09-27 14:24:15 +02004223 int rc, clear_config;
Michal Vasko1d87a922015-08-21 12:57:16 +02004224 struct lys_node *sub;
Pavol Vican47319932016-08-29 09:14:47 +02004225 const struct lys_node *aug_target, *parent;
Radek Krejci27fe55e2016-09-13 17:13:35 +02004226 struct lys_module *mod;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004227
Michal Vasko15b36692016-08-26 15:29:54 +02004228 assert(aug && !aug->target);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004229
Michal Vasko15b36692016-08-26 15:29:54 +02004230 /* resolve target node */
4231 rc = resolve_augment_schema_nodeid(aug->target_name, siblings, (siblings ? NULL : aug->module), &aug_target);
4232 if (rc == -1) {
4233 return -1;
4234 }
4235 if (rc > 0) {
4236 LOGVAL(LYE_INCHAR, LY_VLOG_LYS, aug, aug->target_name[rc - 1], &aug->target_name[rc - 1]);
4237 return -1;
4238 }
4239 if (!aug_target) {
4240 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, aug, "augment", aug->target_name);
4241 return EXIT_FAILURE;
4242 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004243
Radek Krejci27fe55e2016-09-13 17:13:35 +02004244 /* check that we want to connect augment into its target */
4245 mod = lys_main_module(aug->module);
4246 if (!mod->implemented) {
4247 /* it must be augment only to the same module,
4248 * otherwise we do not apply augment in not-implemented
4249 * module. If the module is set to be implemented in future,
4250 * the augment is being resolved and checked again */
4251 for (sub = aug->target; sub; sub = lys_parent(sub)) {
4252 if (lys_node_module(sub) != mod) {
4253 /* this is not an implemented module and the augment
4254 * target some other module, so avoid its connecting
4255 * to the target */
4256 return EXIT_SUCCESS;
4257 }
4258 }
4259 }
4260
Michal Vasko15b36692016-08-26 15:29:54 +02004261 if (!aug->child) {
4262 /* nothing to do */
4263 LOGWRN("Augment \"%s\" without children.", aug->target_name);
Radek Krejci27fe55e2016-09-13 17:13:35 +02004264 goto success;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004265 }
4266
Michal Vaskod58d5962016-03-02 14:29:41 +01004267 /* check for mandatory nodes - if the target node is in another module
4268 * the added nodes cannot be mandatory
4269 */
Michal Vasko15b36692016-08-26 15:29:54 +02004270 if (!aug->parent && (lys_node_module((struct lys_node *)aug) != lys_node_module(aug_target))
Radek Krejcie00d2312016-08-12 15:27:49 +02004271 && (rc = lyp_check_mandatory_augment(aug))) {
4272 return rc;
Michal Vaskod58d5962016-03-02 14:29:41 +01004273 }
4274
Michal Vasko07e89ef2016-03-03 13:28:57 +01004275 /* check augment target type and then augment nodes type */
Michal Vasko15b36692016-08-26 15:29:54 +02004276 if (aug_target->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_CASE | LYS_INPUT | LYS_OUTPUT | LYS_NOTIF)) {
Michal Vasko07e89ef2016-03-03 13:28:57 +01004277 LY_TREE_FOR(aug->child, sub) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02004278 if (!(sub->nodetype & (LYS_ANYDATA | LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST | LYS_USES | LYS_CHOICE))) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004279 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, aug, strnodetype(sub->nodetype), "augment");
4280 LOGVAL(LYE_SPEC, LY_VLOG_LYS, aug, "Cannot augment \"%s\" with a \"%s\".",
Michal Vasko15b36692016-08-26 15:29:54 +02004281 strnodetype(aug_target->nodetype), strnodetype(sub->nodetype));
Michal Vasko07e89ef2016-03-03 13:28:57 +01004282 return -1;
4283 }
4284 }
Michal Vasko15b36692016-08-26 15:29:54 +02004285 } else if (aug_target->nodetype == LYS_CHOICE) {
Michal Vasko07e89ef2016-03-03 13:28:57 +01004286 LY_TREE_FOR(aug->child, sub) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02004287 if (!(sub->nodetype & (LYS_CASE | LYS_ANYDATA | LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST))) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004288 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, aug, strnodetype(sub->nodetype), "augment");
4289 LOGVAL(LYE_SPEC, LY_VLOG_LYS, aug, "Cannot augment \"%s\" with a \"%s\".",
Michal Vasko15b36692016-08-26 15:29:54 +02004290 strnodetype(aug_target->nodetype), strnodetype(sub->nodetype));
Michal Vasko07e89ef2016-03-03 13:28:57 +01004291 return -1;
4292 }
4293 }
4294 } else {
Radek Krejci48464ed2016-03-17 15:44:09 +01004295 LOGVAL(LYE_INARG, LY_VLOG_LYS, aug, aug->target_name, "target-node");
Michal Vasko15b36692016-08-26 15:29:54 +02004296 LOGVAL(LYE_SPEC, LY_VLOG_LYS, aug, "Invalid augment target node type \"%s\".", strnodetype(aug_target->nodetype));
Michal Vasko07e89ef2016-03-03 13:28:57 +01004297 return -1;
4298 }
4299
Radek Krejcic071c542016-01-27 14:57:51 +01004300 /* check identifier uniqueness as in lys_node_addchild() */
Michal Vasko1d87a922015-08-21 12:57:16 +02004301 LY_TREE_FOR(aug->child, sub) {
Michal Vasko15b36692016-08-26 15:29:54 +02004302 if (lys_check_id(sub, (struct lys_node *)aug_target, NULL)) {
Michal Vasko3e6665f2015-08-17 14:00:38 +02004303 return -1;
Radek Krejci07911992015-08-14 15:13:31 +02004304 }
4305 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004306
Michal Vasko15b36692016-08-26 15:29:54 +02004307 /* finally reconnect augmenting data into the target - add them to the target child list,
4308 * by setting aug->target we know the augment is fully resolved now */
4309 aug->target = (struct lys_node *)aug_target;
4310 if (aug->target->child) {
4311 sub = aug->target->child->prev; /* remember current target's last node */
4312 sub->next = aug->child; /* connect augmenting data after target's last node */
4313 aug->target->child->prev = aug->child->prev; /* new target's last node is last augmenting node */
4314 aug->child->prev = sub; /* finish connecting of both child lists */
4315 } else {
4316 aug->target->child = aug->child;
4317 }
4318
Michal Vasko9e635ac2016-10-17 11:44:09 +02004319 /* inherit config information from actual parent */
4320 for(parent = aug_target; parent && !(parent->nodetype & (LYS_NOTIF | LYS_INPUT | LYS_OUTPUT | LYS_RPC)); parent = lys_parent(parent));
4321 clear_config = (parent) ? 1 : 0;
4322 LY_TREE_FOR(aug->child, sub) {
4323 if (inherit_config_flag(sub, aug_target->flags & LYS_CONFIG_MASK, clear_config, 1, 1)) {
4324 return -1;
4325 }
4326 }
4327
Radek Krejci27fe55e2016-09-13 17:13:35 +02004328success:
4329 if (mod->implemented) {
4330 /* make target modules also implemented */
4331 for (sub = aug->target; sub; sub = lys_parent(sub)) {
4332 if (lys_set_implemented(sub->module)) {
4333 return -1;
4334 }
4335 }
4336 }
4337
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004338 return EXIT_SUCCESS;
4339}
4340
Michal Vasko730dfdf2015-08-11 14:48:05 +02004341/**
Pavol Vican855ca622016-09-05 13:07:54 +02004342 * @brief Resolve (find) choice default case. Does not log.
4343 *
4344 * @param[in] choic Choice to use.
4345 * @param[in] dflt Name of the default case.
4346 *
4347 * @return Pointer to the default node or NULL.
4348 */
4349static struct lys_node *
4350resolve_choice_dflt(struct lys_node_choice *choic, const char *dflt)
4351{
4352 struct lys_node *child, *ret;
4353
4354 LY_TREE_FOR(choic->child, child) {
4355 if (child->nodetype == LYS_USES) {
4356 ret = resolve_choice_dflt((struct lys_node_choice *)child, dflt);
4357 if (ret) {
4358 return ret;
4359 }
4360 }
4361
4362 if (ly_strequal(child->name, dflt, 1) && (child->nodetype & (LYS_ANYDATA | LYS_CASE
Radek Krejci2f792db2016-09-12 10:52:33 +02004363 | LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_CHOICE))) {
Pavol Vican855ca622016-09-05 13:07:54 +02004364 return child;
4365 }
4366 }
4367
4368 return NULL;
4369}
4370
4371/**
Michal Vasko730dfdf2015-08-11 14:48:05 +02004372 * @brief Resolve uses, apply augments, refines. Logs directly.
4373 *
Michal Vaskobb211122015-08-19 14:03:11 +02004374 * @param[in] uses Uses to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004375 * @param[in,out] unres List of unresolved items.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004376 *
Michal Vaskodef0db12015-10-07 13:22:48 +02004377 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004378 */
Michal Vasko184521f2015-09-24 13:14:26 +02004379static int
Radek Krejci48464ed2016-03-17 15:44:09 +01004380resolve_uses(struct lys_node_uses *uses, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004381{
4382 struct ly_ctx *ctx;
Pavol Vican855ca622016-09-05 13:07:54 +02004383 struct lys_node *node = NULL, *next, *iter, **refine_nodes = NULL;
Pavol Vican55abd332016-07-12 15:54:49 +02004384 struct lys_node *node_aux, *parent, *tmp;
Radek Krejci200bf712016-08-16 17:11:04 +02004385 struct lys_node_leaflist *llist;
4386 struct lys_node_leaf *leaf;
Radek Krejci76512572015-08-04 09:47:08 +02004387 struct lys_refine *rfn;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004388 struct lys_restr *must, **old_must;
Radek Krejci363bd4a2016-07-29 14:30:20 +02004389 struct lys_iffeature *iff, **old_iff;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004390 int i, j, k, rc, parent_config, clear_config, check_list, check_xpath;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004391 uint8_t size, *old_size;
Radek Krejci363bd4a2016-07-29 14:30:20 +02004392 unsigned int usize, usize1, usize2;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004393
Michal Vasko71e1aa82015-08-12 12:17:51 +02004394 assert(uses->grp);
Michal Vaskoe7708512016-03-11 10:26:55 +01004395 /* HACK just check that the grouping is resolved */
Michal Vaskodef0db12015-10-07 13:22:48 +02004396 assert(!uses->grp->nacm);
Michal Vasko71e1aa82015-08-12 12:17:51 +02004397
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004398 if (!uses->grp->child) {
4399 /* grouping without children, warning was already displayed */
4400 return EXIT_SUCCESS;
4401 }
4402
4403 /* get proper parent (config) flags */
4404 for (node_aux = lys_parent((struct lys_node *)uses); node_aux && (node_aux->nodetype == LYS_USES); node_aux = lys_parent(node_aux));
4405 if (node_aux) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004406 parent_config = node_aux->flags & LYS_CONFIG_MASK;
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004407 } else {
4408 /* default */
Michal Vaskoa86508c2016-08-26 14:30:19 +02004409 parent_config = LYS_CONFIG_W;
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004410 }
4411
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004412 /* copy the data nodes from grouping into the uses context */
Michal Vasko1e62a092015-12-01 12:27:20 +01004413 LY_TREE_FOR(uses->grp->child, node_aux) {
Michal Vaskoe022a562016-09-27 14:24:15 +02004414 node = lys_node_dup(uses->module, (struct lys_node *)uses, node_aux, uses->nacm, unres, 0);
Michal Vasko1e62a092015-12-01 12:27:20 +01004415 if (!node) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004416 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, uses->grp->name, "uses");
4417 LOGVAL(LYE_SPEC, LY_VLOG_LYS, uses, "Copying data from grouping failed.");
Michal Vaskoa86508c2016-08-26 14:30:19 +02004418 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004419 }
Pavol Vican55abd332016-07-12 15:54:49 +02004420 /* test the name of siblings */
4421 LY_TREE_FOR((uses->parent) ? uses->parent->child : lys_main_module(uses->module)->data, tmp) {
Pavol Vican2510ddc2016-07-18 16:23:44 +02004422 if (!(tmp->nodetype & (LYS_USES | LYS_GROUPING | LYS_CASE)) && ly_strequal(tmp->name, node_aux->name, 1)) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004423 goto fail;
Pavol Vican55abd332016-07-12 15:54:49 +02004424 }
4425 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004426 }
Michal Vaskoe022a562016-09-27 14:24:15 +02004427
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004428 ctx = uses->module->ctx;
Michal Vasko4bc590c2016-09-30 12:19:51 +02004429
4430 parent = node;
4431 while (parent && !(parent->nodetype & (LYS_NOTIF | LYS_INPUT | LYS_OUTPUT | LYS_RPC | LYS_GROUPING))) {
4432 if (parent->nodetype == LYS_AUGMENT) {
4433 if (!((struct lys_node_augment *)parent)->target) {
4434 break;
4435 } else {
4436 parent = ((struct lys_node_augment *)parent)->target;
4437 }
4438 } else {
4439 parent = parent->parent;
4440 }
4441 }
Michal Vaskoe022a562016-09-27 14:24:15 +02004442 if (parent) {
Michal Vasko4bc590c2016-09-30 12:19:51 +02004443 if (parent->nodetype & (LYS_GROUPING | LYS_AUGMENT)) {
4444 /* we are still in some other unresolved grouping or augment, unable to check lists */
Michal Vaskoe022a562016-09-27 14:24:15 +02004445 check_list = 0;
4446 clear_config = 0;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004447 check_xpath = 0;
Michal Vaskoe022a562016-09-27 14:24:15 +02004448 } else {
4449 check_list = 0;
4450 clear_config = 1;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004451 check_xpath = 1;
Michal Vaskoe022a562016-09-27 14:24:15 +02004452 }
4453 } else {
4454 check_list = 1;
4455 clear_config = 0;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004456 check_xpath = 1;
Michal Vaskoe022a562016-09-27 14:24:15 +02004457 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004458
Michal Vaskoa86508c2016-08-26 14:30:19 +02004459 if (parent_config) {
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004460 assert(uses->child);
Michal Vasko9e635ac2016-10-17 11:44:09 +02004461 if (inherit_config_flag(uses->child, parent_config, clear_config, check_list, check_xpath)) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004462 goto fail;
4463 }
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004464 }
4465
Michal Vaskodef0db12015-10-07 13:22:48 +02004466 /* we managed to copy the grouping, the rest must be possible to resolve */
4467
Pavol Vican855ca622016-09-05 13:07:54 +02004468 if (uses->refine_size) {
4469 refine_nodes = malloc(uses->refine_size * sizeof *refine_nodes);
4470 if (!refine_nodes) {
4471 LOGMEM;
4472 goto fail;
4473 }
4474 }
4475
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004476 /* apply refines */
4477 for (i = 0; i < uses->refine_size; i++) {
4478 rfn = &uses->refine[i];
Michal Vasko3edeaf72016-02-11 13:17:43 +01004479 rc = resolve_descendant_schema_nodeid(rfn->target_name, uses->child, LYS_NO_RPC_NOTIF_NODE,
Radek Krejcif3c71de2016-04-11 12:45:46 +02004480 1, 0, (const struct lys_node **)&node);
Michal Vasko9bb061b2016-02-12 11:00:19 +01004481 if (rc || !node) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004482 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, rfn->target_name, "refine");
Michal Vaskoa86508c2016-08-26 14:30:19 +02004483 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004484 }
4485
Radek Krejci1d82ef62015-08-07 14:44:40 +02004486 if (rfn->target_type && !(node->nodetype & rfn->target_type)) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004487 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, rfn->target_name, "refine");
4488 LOGVAL(LYE_SPEC, LY_VLOG_LYS, uses, "Refine substatements not applicable to the target-node.");
Michal Vaskoa86508c2016-08-26 14:30:19 +02004489 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004490 }
Pavol Vican855ca622016-09-05 13:07:54 +02004491 refine_nodes[i] = node;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004492
4493 /* description on any nodetype */
4494 if (rfn->dsc) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004495 lydict_remove(ctx, node->dsc);
4496 node->dsc = lydict_insert(ctx, rfn->dsc, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004497 }
4498
4499 /* reference on any nodetype */
4500 if (rfn->ref) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004501 lydict_remove(ctx, node->ref);
4502 node->ref = lydict_insert(ctx, rfn->ref, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004503 }
4504
4505 /* config on any nodetype */
Michal Vaskoe022a562016-09-27 14:24:15 +02004506 if ((rfn->flags & LYS_CONFIG_MASK) && !clear_config) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004507 node->flags &= ~LYS_CONFIG_MASK;
4508 node->flags |= (rfn->flags & LYS_CONFIG_MASK);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004509 }
4510
4511 /* default value ... */
Radek Krejci200bf712016-08-16 17:11:04 +02004512 if (rfn->dflt_size) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004513 if (node->nodetype == LYS_LEAF) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004514 /* leaf */
Radek Krejci200bf712016-08-16 17:11:04 +02004515 leaf = (struct lys_node_leaf *)node;
4516
4517 lydict_remove(ctx, leaf->dflt);
4518 leaf->dflt = lydict_insert(ctx, rfn->dflt[0], 0);
4519
4520 /* check the default value */
4521 if (unres_schema_add_str(leaf->module, unres, &leaf->type, UNRES_TYPE_DFLT, leaf->dflt) == -1) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004522 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004523 }
Radek Krejci200bf712016-08-16 17:11:04 +02004524 } else if (node->nodetype == LYS_LEAFLIST) {
4525 /* leaf-list */
4526 llist = (struct lys_node_leaflist *)node;
4527
4528 /* remove complete set of defaults in target */
4529 for (i = 0; i < llist->dflt_size; i++) {
4530 lydict_remove(ctx, llist->dflt[i]);
4531 }
4532 free(llist->dflt);
4533
4534 /* copy the default set from refine */
4535 llist->dflt_size = rfn->dflt_size;
4536 llist->dflt = malloc(llist->dflt_size * sizeof *llist->dflt);
4537 for (i = 0; i < llist->dflt_size; i++) {
4538 llist->dflt[i] = lydict_insert(ctx, rfn->dflt[i], 0);
4539 }
4540
4541 /* check default value */
4542 for (i = 0; i < llist->dflt_size; i++) {
4543 if (unres_schema_add_str(llist->module, unres, &llist->type, UNRES_TYPE_DFLT, llist->dflt[i]) == -1) {
Pavol Vican855ca622016-09-05 13:07:54 +02004544 goto fail;
Radek Krejci200bf712016-08-16 17:11:04 +02004545 }
4546 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004547 }
4548 }
4549
4550 /* mandatory on leaf, anyxml or choice */
Radek Krejci1574a8d2015-08-03 14:16:52 +02004551 if (rfn->flags & LYS_MAND_MASK) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02004552 if (node->nodetype & (LYS_LEAF | LYS_ANYDATA | LYS_CHOICE)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004553 /* remove current value */
Radek Krejci1d82ef62015-08-07 14:44:40 +02004554 node->flags &= ~LYS_MAND_MASK;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004555
4556 /* set new value */
Radek Krejci1d82ef62015-08-07 14:44:40 +02004557 node->flags |= (rfn->flags & LYS_MAND_MASK);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004558 }
Pavol Vican855ca622016-09-05 13:07:54 +02004559 if (rfn->flags & LYS_MAND_TRUE) {
4560 /* check if node has default value */
4561 if ((node->nodetype & LYS_LEAF) && ((struct lys_node_leaf *)node)->dflt) {
4562 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "The \"mandatory\" statement is forbidden on leaf with \"default\".");
4563 goto fail;
4564 }
4565 if ((node->nodetype & LYS_CHOICE) && ((struct lys_node_choice *)node)->dflt) {
4566 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "The \"mandatory\" statement is forbidden on choices with \"default\".");
4567 goto fail;
4568 }
4569 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004570 }
4571
4572 /* presence on container */
Radek Krejci1d82ef62015-08-07 14:44:40 +02004573 if ((node->nodetype & LYS_CONTAINER) && rfn->mod.presence) {
4574 lydict_remove(ctx, ((struct lys_node_container *)node)->presence);
4575 ((struct lys_node_container *)node)->presence = lydict_insert(ctx, rfn->mod.presence, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004576 }
4577
4578 /* min/max-elements on list or leaf-list */
Radek Krejci1d82ef62015-08-07 14:44:40 +02004579 if (node->nodetype == LYS_LIST) {
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004580 if (rfn->flags & LYS_RFN_MINSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004581 ((struct lys_node_list *)node)->min = rfn->mod.list.min;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004582 }
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004583 if (rfn->flags & LYS_RFN_MAXSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004584 ((struct lys_node_list *)node)->max = rfn->mod.list.max;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004585 }
Radek Krejci1d82ef62015-08-07 14:44:40 +02004586 } else if (node->nodetype == LYS_LEAFLIST) {
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004587 if (rfn->flags & LYS_RFN_MINSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004588 ((struct lys_node_leaflist *)node)->min = rfn->mod.list.min;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004589 }
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004590 if (rfn->flags & LYS_RFN_MAXSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004591 ((struct lys_node_leaflist *)node)->max = rfn->mod.list.max;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004592 }
4593 }
4594
4595 /* must in leaf, leaf-list, list, container or anyxml */
4596 if (rfn->must_size) {
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004597 switch (node->nodetype) {
4598 case LYS_LEAF:
4599 old_size = &((struct lys_node_leaf *)node)->must_size;
4600 old_must = &((struct lys_node_leaf *)node)->must;
4601 break;
4602 case LYS_LEAFLIST:
4603 old_size = &((struct lys_node_leaflist *)node)->must_size;
4604 old_must = &((struct lys_node_leaflist *)node)->must;
4605 break;
4606 case LYS_LIST:
4607 old_size = &((struct lys_node_list *)node)->must_size;
4608 old_must = &((struct lys_node_list *)node)->must;
4609 break;
4610 case LYS_CONTAINER:
4611 old_size = &((struct lys_node_container *)node)->must_size;
4612 old_must = &((struct lys_node_container *)node)->must;
4613 break;
4614 case LYS_ANYXML:
Radek Krejcibf2abff2016-08-23 15:51:52 +02004615 case LYS_ANYDATA:
4616 old_size = &((struct lys_node_anydata *)node)->must_size;
4617 old_must = &((struct lys_node_anydata *)node)->must;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004618 break;
4619 default:
4620 LOGINT;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004621 goto fail;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004622 }
4623
4624 size = *old_size + rfn->must_size;
4625 must = realloc(*old_must, size * sizeof *rfn->must);
4626 if (!must) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004627 LOGMEM;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004628 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004629 }
Pavol Vican855ca622016-09-05 13:07:54 +02004630 for (k = 0, j = *old_size; k < rfn->must_size; k++, j++) {
4631 must[j].expr = lydict_insert(ctx, rfn->must[k].expr, 0);
4632 must[j].dsc = lydict_insert(ctx, rfn->must[k].dsc, 0);
4633 must[j].ref = lydict_insert(ctx, rfn->must[k].ref, 0);
4634 must[j].eapptag = lydict_insert(ctx, rfn->must[k].eapptag, 0);
4635 must[j].emsg = lydict_insert(ctx, rfn->must[k].emsg, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004636 }
4637
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004638 *old_must = must;
4639 *old_size = size;
Michal Vasko508a50d2016-09-07 14:50:33 +02004640
4641 /* check XPath dependencies again */
4642 if (unres_schema_add_node(node->module, unres, node, UNRES_XPATH, NULL) == -1) {
4643 goto fail;
4644 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004645 }
Radek Krejci363bd4a2016-07-29 14:30:20 +02004646
4647 /* if-feature in leaf, leaf-list, list, container or anyxml */
4648 if (rfn->iffeature_size) {
4649 old_size = &node->iffeature_size;
4650 old_iff = &node->iffeature;
4651
4652 size = *old_size + rfn->iffeature_size;
4653 iff = realloc(*old_iff, size * sizeof *rfn->iffeature);
4654 if (!iff) {
4655 LOGMEM;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004656 goto fail;
Radek Krejci363bd4a2016-07-29 14:30:20 +02004657 }
Pavol Vican855ca622016-09-05 13:07:54 +02004658 for (k = 0, j = *old_size; k < rfn->iffeature_size; k++, j++) {
4659 resolve_iffeature_getsizes(&rfn->iffeature[k], &usize1, &usize2);
Radek Krejci363bd4a2016-07-29 14:30:20 +02004660 if (usize1) {
4661 /* there is something to duplicate */
4662 /* duplicate compiled expression */
4663 usize = (usize1 / 4) + (usize1 % 4) ? 1 : 0;
4664 iff[j].expr = malloc(usize * sizeof *iff[j].expr);
Pavol Vican855ca622016-09-05 13:07:54 +02004665 memcpy(iff[j].expr, rfn->iffeature[k].expr, usize * sizeof *iff[j].expr);
Radek Krejci363bd4a2016-07-29 14:30:20 +02004666
4667 /* duplicate list of feature pointers */
Pavol Vican855ca622016-09-05 13:07:54 +02004668 iff[j].features = malloc(usize2 * sizeof *iff[k].features);
4669 memcpy(iff[j].features, rfn->iffeature[k].features, usize2 * sizeof *iff[j].features);
Radek Krejci363bd4a2016-07-29 14:30:20 +02004670 }
4671 }
4672
4673 *old_iff = iff;
4674 *old_size = size;
4675 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004676 }
4677
4678 /* apply augments */
4679 for (i = 0; i < uses->augment_size; i++) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004680 rc = resolve_augment(&uses->augment[i], uses->child);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004681 if (rc) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004682 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004683 }
4684 }
4685
Pavol Vican855ca622016-09-05 13:07:54 +02004686 /* check refines */
4687 for (i = 0; i < uses->refine_size; i++) {
4688 node = refine_nodes[i];
4689 rfn = &uses->refine[i];
4690
4691 /* config on any nodetype */
Michal Vaskoe022a562016-09-27 14:24:15 +02004692 if ((rfn->flags & LYS_CONFIG_MASK) && !clear_config) {
Pavol Vican855ca622016-09-05 13:07:54 +02004693 for (parent = lys_parent(node); parent && parent->nodetype == LYS_USES; parent = lys_parent(parent));
4694 if (parent && parent->nodetype != LYS_GROUPING &&
4695 ((parent->flags & LYS_CONFIG_MASK) != (rfn->flags & LYS_CONFIG_MASK)) &&
4696 (rfn->flags & LYS_CONFIG_W)) {
4697 /* setting config true under config false is prohibited */
4698 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, "config", "refine");
4699 LOGVAL(LYE_SPEC, LY_VLOG_LYS, uses,
4700 "changing config from 'false' to 'true' is prohibited while "
4701 "the target's parent is still config 'false'.");
4702 goto fail;
4703 }
4704
4705 /* inherit config change to the target children */
4706 LY_TREE_DFS_BEGIN(node->child, next, iter) {
4707 if (rfn->flags & LYS_CONFIG_W) {
4708 if (iter->flags & LYS_CONFIG_SET) {
4709 /* config is set explicitely, go to next sibling */
4710 next = NULL;
4711 goto nextsibling;
4712 }
4713 } else { /* LYS_CONFIG_R */
4714 if ((iter->flags & LYS_CONFIG_SET) && (iter->flags & LYS_CONFIG_W)) {
4715 /* error - we would have config data under status data */
4716 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, "config", "refine");
4717 LOGVAL(LYE_SPEC, LY_VLOG_LYS, uses,
4718 "changing config from 'true' to 'false' is prohibited while the target "
4719 "has still a children with explicit config 'true'.");
4720 goto fail;
4721 }
4722 }
4723 /* change config */
4724 iter->flags &= ~LYS_CONFIG_MASK;
4725 iter->flags |= (rfn->flags & LYS_CONFIG_MASK);
4726
4727 /* select next iter - modified LY_TREE_DFS_END */
4728 if (iter->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
4729 next = NULL;
4730 } else {
4731 next = iter->child;
4732 }
4733nextsibling:
4734 if (!next) {
4735 /* try siblings */
4736 next = iter->next;
4737 }
4738 while (!next) {
4739 /* parent is already processed, go to its sibling */
4740 iter = lys_parent(iter);
4741
4742 /* no siblings, go back through parents */
4743 if (iter == node) {
4744 /* we are done, no next element to process */
4745 break;
4746 }
4747 next = iter->next;
4748 }
4749 }
4750 }
4751
4752 /* default value */
4753 if (rfn->dflt_size && node->nodetype == LYS_CHOICE) {
4754 /* choice */
4755
4756 ((struct lys_node_choice *)node)->dflt = resolve_choice_dflt((struct lys_node_choice *)node,
4757 rfn->dflt[0]);
4758 if (!((struct lys_node_choice *)node)->dflt) {
4759 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, rfn->dflt[0], "default");
4760 goto fail;
4761 }
4762 if (lyp_check_mandatory_choice(node)) {
4763 goto fail;
4764 }
4765 }
4766
4767 /* min/max-elements on list or leaf-list */
4768 if (node->nodetype == LYS_LIST) {
4769 if (((struct lys_node_list *)node)->min > ((struct lys_node_list *)node)->max) {
4770 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Invalid value \"%d\" of \"%s\".", rfn->mod.list.min, "min-elements");
4771 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "\"min-elements\" is bigger than \"max-elements\".");
4772 goto fail;
4773 }
4774 } else if (node->nodetype == LYS_LEAFLIST) {
4775 if (((struct lys_node_leaflist *)node)->min > ((struct lys_node_leaflist *)node)->max) {
4776 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Invalid value \"%d\" of \"%s\".", rfn->mod.list.min, "min-elements");
4777 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "\"min-elements\" is bigger than \"max-elements\".");
4778 goto fail;
4779 }
4780 }
4781
4782 /* additional checks */
4783 if (node->nodetype == LYS_LEAFLIST) {
4784 llist = (struct lys_node_leaflist *)node;
4785 if (llist->dflt_size && llist->min) {
4786 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_NONE, NULL, rfn->dflt_size ? "default" : "min-elements", "refine");
4787 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL,
4788 "The \"min-elements\" statement with non-zero value is forbidden on leaf-lists with the \"default\" statement.");
4789 goto fail;
4790 }
4791 }
4792 if ((rfn->flags & LYS_MAND_TRUE) || rfn->mod.list.min) {
4793 /* check for mandatory node in default case, first find the closest parent choice to the changed node */
4794 for (parent = node->parent;
4795 parent && !(parent->nodetype & (LYS_CHOICE | LYS_GROUPING | LYS_ACTION | LYS_USES));
4796 parent = parent->parent) {
4797 if (parent->nodetype == LYS_CONTAINER && ((struct lys_node_container *)parent)->presence) {
4798 /* stop also on presence containers */
4799 break;
4800 }
4801 }
4802 /* and if it is a choice with the default case, check it for presence of a mandatory node in it */
4803 if (parent && parent->nodetype == LYS_CHOICE && ((struct lys_node_choice *)parent)->dflt) {
4804 if (lyp_check_mandatory_choice(parent)) {
4805 goto fail;
4806 }
4807 }
4808 }
4809 }
4810 free(refine_nodes);
4811
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004812 return EXIT_SUCCESS;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004813
4814fail:
4815 LY_TREE_FOR_SAFE(uses->child, next, iter) {
4816 lys_node_free(iter, NULL, 0);
4817 }
Pavol Vican855ca622016-09-05 13:07:54 +02004818 free(refine_nodes);
Michal Vaskoa86508c2016-08-26 14:30:19 +02004819 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004820}
4821
Radek Krejci018f1f52016-08-03 16:01:20 +02004822static int
4823identity_backlink_update(struct lys_ident *der, struct lys_ident *base)
4824{
4825 int i;
4826
4827 assert(der && base);
4828
4829 base->der = ly_realloc(base->der, (base->der_size + 1) * sizeof *(base->der));
4830 if (!base->der) {
4831 LOGMEM;
4832 return EXIT_FAILURE;
4833 }
4834 base->der[base->der_size++] = der;
4835
4836 for (i = 0; i < base->base_size; i++) {
4837 if (identity_backlink_update(der, base->base[i])) {
4838 return EXIT_FAILURE;
4839 }
4840 }
4841
4842 return EXIT_SUCCESS;
4843}
4844
Michal Vasko730dfdf2015-08-11 14:48:05 +02004845/**
4846 * @brief Resolve base identity recursively. Does not log.
4847 *
4848 * @param[in] module Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02004849 * @param[in] ident Identity to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004850 * @param[in] basename Base name of the identity.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004851 * @param[out] ret Pointer to the resolved identity. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004852 *
Radek Krejci219fa612016-08-15 10:36:51 +02004853 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on crucial error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004854 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004855static int
Michal Vasko1e62a092015-12-01 12:27:20 +01004856resolve_base_ident_sub(const struct lys_module *module, struct lys_ident *ident, const char *basename,
Radek Krejci018f1f52016-08-03 16:01:20 +02004857 struct unres_schema *unres, struct lys_ident **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004858{
Michal Vaskof02e3742015-08-05 16:27:02 +02004859 uint32_t i, j;
Radek Krejci018f1f52016-08-03 16:01:20 +02004860 struct lys_ident *base = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004861
Radek Krejcicf509982015-12-15 09:22:44 +01004862 assert(ret);
4863
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004864 /* search module */
4865 for (i = 0; i < module->ident_size; i++) {
4866 if (!strcmp(basename, module->ident[i].name)) {
4867
4868 if (!ident) {
4869 /* just search for type, so do not modify anything, just return
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01004870 * the base identity pointer */
Radek Krejcicf509982015-12-15 09:22:44 +01004871 *ret = &module->ident[i];
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004872 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004873 }
4874
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01004875 base = &module->ident[i];
4876 goto matchfound;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004877 }
4878 }
4879
4880 /* search submodules */
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01004881 for (j = 0; j < module->inc_size && module->inc[j].submodule; j++) {
4882 for (i = 0; i < module->inc[j].submodule->ident_size; i++) {
4883 if (!strcmp(basename, module->inc[j].submodule->ident[i].name)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004884
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01004885 if (!ident) {
4886 *ret = &module->inc[j].submodule->ident[i];
4887 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004888 }
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01004889
4890 base = &module->inc[j].submodule->ident[i];
4891 goto matchfound;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004892 }
4893 }
4894 }
4895
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01004896matchfound:
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004897 /* we found it somewhere */
Radek Krejcibabbff82016-02-19 13:31:37 +01004898 if (base) {
Radek Krejci018f1f52016-08-03 16:01:20 +02004899 /* is it already completely resolved? */
4900 for (i = 0; i < unres->count; i++) {
Radek Krejciba7b1cc2016-08-08 13:44:43 +02004901 if ((unres->item[i] == base) && (unres->type[i] == UNRES_IDENT)) {
Radek Krejci018f1f52016-08-03 16:01:20 +02004902 /* identity found, but not yet resolved, so do not return it in *res and try it again later */
4903
4904 /* simple check for circular reference,
4905 * the complete check is done as a side effect of using only completely
4906 * resolved identities (previous check of unres content) */
4907 if (ly_strequal((const char *)unres->str_snode[i], ident->name, 1)) {
4908 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, basename, "base");
4909 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Circular reference of \"%s\" identity.", basename);
Radek Krejci219fa612016-08-15 10:36:51 +02004910 return -1;
Radek Krejci018f1f52016-08-03 16:01:20 +02004911 }
4912
Radek Krejci06f64ed2016-08-15 11:07:44 +02004913 return EXIT_FAILURE;
Radek Krejcibabbff82016-02-19 13:31:37 +01004914 }
4915 }
Radek Krejci018f1f52016-08-03 16:01:20 +02004916
Radek Krejcibabbff82016-02-19 13:31:37 +01004917 /* checks done, store the result */
Radek Krejci018f1f52016-08-03 16:01:20 +02004918 *ret = base;
Pavol Vicanfdab9f92016-09-07 15:23:27 +02004919 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004920 }
4921
Radek Krejci219fa612016-08-15 10:36:51 +02004922 /* base not found (maybe a forward reference) */
4923 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004924}
4925
Michal Vasko730dfdf2015-08-11 14:48:05 +02004926/**
4927 * @brief Resolve base identity. Logs directly.
4928 *
4929 * @param[in] module Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02004930 * @param[in] ident Identity to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004931 * @param[in] basename Base name of the identity.
Radek Krejcibabbff82016-02-19 13:31:37 +01004932 * @param[in] parent Either "type" or "identity".
Radek Krejcicf509982015-12-15 09:22:44 +01004933 * @param[in,out] type Type structure where we want to resolve identity. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004934 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004935 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004936 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004937static int
Michal Vaskof2d43962016-09-02 11:10:16 +02004938resolve_base_ident(const struct lys_module *module, struct lys_ident *ident, const char *basename, const char *parent,
Radek Krejci018f1f52016-08-03 16:01:20 +02004939 struct lys_type *type, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004940{
4941 const char *name;
Radek Krejci219fa612016-08-15 10:36:51 +02004942 int mod_name_len = 0, rc;
Radek Krejcicf509982015-12-15 09:22:44 +01004943 struct lys_ident *target, **ret;
Radek Krejci4372b4e2016-04-14 17:42:16 +02004944 uint16_t flags;
Radek Krejcicf509982015-12-15 09:22:44 +01004945 struct lys_module *mod;
4946
4947 assert((ident && !type) || (!ident && type));
4948
4949 if (!type) {
4950 /* have ident to resolve */
4951 ret = &target;
4952 flags = ident->flags;
4953 mod = ident->module;
4954 } else {
4955 /* have type to fill */
Michal Vaskof2d43962016-09-02 11:10:16 +02004956 ++type->info.ident.count;
4957 type->info.ident.ref = ly_realloc(type->info.ident.ref, type->info.ident.count * sizeof *type->info.ident.ref);
4958 if (!type->info.ident.ref) {
4959 LOGMEM;
4960 return -1;
4961 }
4962
4963 ret = &type->info.ident.ref[type->info.ident.count - 1];
Radek Krejcicf509982015-12-15 09:22:44 +01004964 flags = type->parent->flags;
4965 mod = type->parent->module;
4966 }
Michal Vaskof2006002016-04-21 16:28:15 +02004967 *ret = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004968
4969 /* search for the base identity */
4970 name = strchr(basename, ':');
4971 if (name) {
4972 /* set name to correct position after colon */
Michal Vasko2d851a92015-10-20 16:16:36 +02004973 mod_name_len = name - basename;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004974 name++;
4975
Michal Vasko2d851a92015-10-20 16:16:36 +02004976 if (!strncmp(basename, module->name, mod_name_len) && !module->name[mod_name_len]) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004977 /* prefix refers to the current module, ignore it */
Michal Vasko2d851a92015-10-20 16:16:36 +02004978 mod_name_len = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004979 }
4980 } else {
4981 name = basename;
4982 }
4983
Radek Krejcic071c542016-01-27 14:57:51 +01004984 /* get module where to search */
4985 module = lys_get_import_module(module, NULL, 0, mod_name_len ? basename : NULL, mod_name_len);
4986 if (!module) {
4987 /* identity refers unknown data model */
Radek Krejci02a04992016-03-17 16:06:37 +01004988 LOGVAL(LYE_INMOD, LY_VLOG_NONE, NULL, basename);
Radek Krejcic071c542016-01-27 14:57:51 +01004989 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004990 }
4991
Radek Krejcic071c542016-01-27 14:57:51 +01004992 /* search in the identified module ... */
Radek Krejci219fa612016-08-15 10:36:51 +02004993 rc = resolve_base_ident_sub(module, ident, name, unres, ret);
4994 if (!rc) {
4995 assert(*ret);
4996
4997 /* check status */
4998 if (lyp_check_status(flags, mod, ident ? ident->name : "of type",
4999 (*ret)->flags, (*ret)->module, (*ret)->name, NULL)) {
5000 rc = -1;
Pavol Vicanfdab9f92016-09-07 15:23:27 +02005001 } else {
5002 if (ident) {
5003 ident->base[ident->base_size++] = *ret;
5004
5005 /* maintain backlinks to the derived identities */
5006 rc = identity_backlink_update(ident, *ret) ? -1 : EXIT_SUCCESS;
5007 }
Radek Krejci219fa612016-08-15 10:36:51 +02005008 }
5009 } else if (rc == EXIT_FAILURE) {
5010 LOGVAL(LYE_INRESOLV, LY_VLOG_NONE, NULL, parent, basename);
Pavol Vican053a2882016-09-05 14:40:33 +02005011 if (type) {
5012 --type->info.ident.count;
5013 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005014 }
5015
Radek Krejci219fa612016-08-15 10:36:51 +02005016 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005017}
5018
Michal Vasko730dfdf2015-08-11 14:48:05 +02005019/**
Michal Vaskof39142b2015-10-21 11:40:05 +02005020 * @brief Resolve JSON data format identityref. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005021 *
Michal Vaskof2d43962016-09-02 11:10:16 +02005022 * @param[in] type Identityref type.
Michal Vaskofb0873c2015-08-21 09:00:07 +02005023 * @param[in] ident_name Identityref name.
Radek Krejciadb57612016-02-16 13:34:34 +01005024 * @param[in] node Node where the identityref is being resolved
Michal Vasko730dfdf2015-08-11 14:48:05 +02005025 *
5026 * @return Pointer to the identity resolvent, NULL on error.
5027 */
Radek Krejcia52656e2015-08-05 13:41:50 +02005028struct lys_ident *
Michal Vaskof2d43962016-09-02 11:10:16 +02005029resolve_identref(struct lys_type *type, const char *ident_name, struct lyd_node *node)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005030{
Michal Vaskoc633ca02015-08-21 14:03:51 +02005031 const char *mod_name, *name;
Michal Vaskof2d43962016-09-02 11:10:16 +02005032 int mod_name_len, rc, i, j;
5033 struct lys_ident *der, *cur;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005034
Michal Vaskof2d43962016-09-02 11:10:16 +02005035 if (!type || (!type->info.ident.count && !type->der) || !ident_name) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005036 return NULL;
5037 }
5038
Michal Vaskoc633ca02015-08-21 14:03:51 +02005039 rc = parse_node_identifier(ident_name, &mod_name, &mod_name_len, &name, NULL);
Michal Vaskob43bb3c2016-03-17 15:00:27 +01005040 if (rc < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01005041 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, ident_name[-rc], &ident_name[-rc]);
Michal Vaskofb0873c2015-08-21 09:00:07 +02005042 return NULL;
Michal Vaskob43bb3c2016-03-17 15:00:27 +01005043 } else if (rc < (signed)strlen(ident_name)) {
Radek Krejci02a04992016-03-17 16:06:37 +01005044 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, ident_name[rc], &ident_name[rc]);
Michal Vaskofb0873c2015-08-21 09:00:07 +02005045 return NULL;
5046 }
5047
Michal Vaskof2d43962016-09-02 11:10:16 +02005048 /* go through all the bases in all the derived types */
5049 while (type->der) {
5050 for (i = 0; i < type->info.ident.count; ++i) {
5051 cur = type->info.ident.ref[i];
5052 if (!strcmp(cur->name, name) && (!mod_name
5053 || (!strncmp(cur->module->name, mod_name, mod_name_len) && !cur->module->name[mod_name_len]))) {
5054 goto match;
5055 }
Michal Vaskofb0873c2015-08-21 09:00:07 +02005056
Michal Vaskof2d43962016-09-02 11:10:16 +02005057 for (j = 0; j < cur->der_size; j++) {
5058 der = cur->der[j]; /* shortcut */
5059 if (!strcmp(der->name, name) &&
5060 (!mod_name || (!strncmp(der->module->name, mod_name, mod_name_len) && !der->module->name[mod_name_len]))) {
5061 /* we have match */
5062 cur = der;
5063 goto match;
5064 }
5065 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005066 }
Michal Vaskof2d43962016-09-02 11:10:16 +02005067 type = &type->der->type;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005068 }
5069
Radek Krejci48464ed2016-03-17 15:44:09 +01005070 LOGVAL(LYE_INRESOLV, LY_VLOG_LYD, node, "identityref", ident_name);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005071 return NULL;
Radek Krejcif1ee2e22016-08-02 16:36:48 +02005072
5073match:
Michal Vaskof2d43962016-09-02 11:10:16 +02005074 for (i = 0; i < cur->iffeature_size; i++) {
5075 if (!resolve_iffeature(&cur->iffeature[i])) {
5076 LOGVAL(LYE_INVAL, LY_VLOG_LYD, node, cur->name, node->schema->name);
Radek Krejcif1ee2e22016-08-02 16:36:48 +02005077 LOGVAL(LYE_SPEC, LY_VLOG_LYD, node, "Identity \"%s\" is disabled by its if-feature condition.",
Michal Vaskof2d43962016-09-02 11:10:16 +02005078 cur->name);
Radek Krejcif1ee2e22016-08-02 16:36:48 +02005079 return NULL;
5080 }
5081 }
Michal Vaskof2d43962016-09-02 11:10:16 +02005082 return cur;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005083}
5084
Michal Vasko730dfdf2015-08-11 14:48:05 +02005085/**
Michal Vaskobb211122015-08-19 14:03:11 +02005086 * @brief Resolve unresolved uses. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005087 *
Michal Vaskobb211122015-08-19 14:03:11 +02005088 * @param[in] uses Uses to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005089 * @param[in] unres Specific unres item.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005090 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005091 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005092 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005093static int
Radek Krejci48464ed2016-03-17 15:44:09 +01005094resolve_unres_schema_uses(struct lys_node_uses *uses, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005095{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005096 int rc;
Radek Krejci010e54b2016-03-15 09:40:34 +01005097 struct lys_node *par_grp;
Michal Vaskoe91afce2015-08-12 12:21:00 +02005098
Radek Krejci010e54b2016-03-15 09:40:34 +01005099 /* HACK: when a grouping has uses inside, all such uses have to be resolved before the grouping itself
5100 * is used in some uses. When we see such a uses, the grouping's nacm member (not used in grouping)
5101 * is used to store number of so far unresolved uses. The grouping cannot be used unless the nacm
5102 * value is decreased back to 0. To remember that the uses already increased grouping's nacm, the
5103 * LYS_USESGRP flag is used. */
Michal Vaskodcf98e62016-05-05 17:53:53 +02005104 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 +02005105
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005106 if (!uses->grp) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01005107 rc = resolve_uses_schema_nodeid(uses->name, (const struct lys_node *)uses, (const struct lys_node_grp **)&uses->grp);
5108 if (rc == -1) {
Michal Vasko92981a62016-10-14 10:25:16 +02005109 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, uses, "uses", uses->name);
Michal Vasko3edeaf72016-02-11 13:17:43 +01005110 return -1;
5111 } else if (rc > 0) {
Radek Krejci48464ed2016-03-17 15:44:09 +01005112 LOGVAL(LYE_INCHAR, LY_VLOG_LYS, uses, uses->name[rc - 1], &uses->name[rc - 1]);
Michal Vasko3edeaf72016-02-11 13:17:43 +01005113 return -1;
5114 } else if (!uses->grp) {
Radek Krejci010e54b2016-03-15 09:40:34 +01005115 if (par_grp && !(uses->flags & LYS_USESGRP)) {
Radek Krejci4372b4e2016-04-14 17:42:16 +02005116 /* hack - in contrast to lys_node, lys_node_grp has bigger nacm field
5117 * (and smaller flags - it uses only a limited set of flags)
5118 */
5119 ((struct lys_node_grp *)par_grp)->nacm++;
Radek Krejci010e54b2016-03-15 09:40:34 +01005120 uses->flags |= LYS_USESGRP;
Michal Vasko407f1bb2015-09-23 15:51:07 +02005121 }
Michal Vasko92981a62016-10-14 10:25:16 +02005122 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, uses, "uses", uses->name);
Michal Vasko3edeaf72016-02-11 13:17:43 +01005123 return EXIT_FAILURE;
Michal Vasko12e30842015-08-04 11:54:00 +02005124 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005125 }
5126
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005127 if (uses->grp->nacm) {
Radek Krejci010e54b2016-03-15 09:40:34 +01005128 if (par_grp && !(uses->flags & LYS_USESGRP)) {
Radek Krejci4372b4e2016-04-14 17:42:16 +02005129 ((struct lys_node_grp *)par_grp)->nacm++;
Radek Krejci010e54b2016-03-15 09:40:34 +01005130 uses->flags |= LYS_USESGRP;
Radek Krejcie00d2312016-08-12 15:27:49 +02005131 } else {
5132 /* instantiate grouping only when it is completely resolved */
5133 uses->grp = NULL;
Michal Vasko407f1bb2015-09-23 15:51:07 +02005134 }
Michal Vasko92981a62016-10-14 10:25:16 +02005135 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, uses, "uses", uses->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005136 return EXIT_FAILURE;
5137 }
5138
Radek Krejci48464ed2016-03-17 15:44:09 +01005139 rc = resolve_uses(uses, unres);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005140 if (!rc) {
5141 /* decrease unres count only if not first try */
Radek Krejci010e54b2016-03-15 09:40:34 +01005142 if (par_grp && (uses->flags & LYS_USESGRP)) {
Radek Krejci4372b4e2016-04-14 17:42:16 +02005143 if (!((struct lys_node_grp *)par_grp)->nacm) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005144 LOGINT;
5145 return -1;
5146 }
Radek Krejci4372b4e2016-04-14 17:42:16 +02005147 ((struct lys_node_grp *)par_grp)->nacm--;
Radek Krejci010e54b2016-03-15 09:40:34 +01005148 uses->flags &= ~LYS_USESGRP;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005149 }
Radek Krejcicf509982015-12-15 09:22:44 +01005150
5151 /* check status */
Radek Krejcic6556022016-01-27 15:16:45 +01005152 if (lyp_check_status(uses->flags, uses->module, "of uses",
Radek Krejciadb57612016-02-16 13:34:34 +01005153 uses->grp->flags, uses->grp->module, uses->grp->name,
Radek Krejci48464ed2016-03-17 15:44:09 +01005154 (struct lys_node *)uses)) {
Radek Krejcicf509982015-12-15 09:22:44 +01005155 return -1;
5156 }
5157
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005158 return EXIT_SUCCESS;
5159 }
5160
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005161 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005162}
5163
Michal Vasko730dfdf2015-08-11 14:48:05 +02005164/**
Michal Vasko9957e592015-08-17 15:04:09 +02005165 * @brief Resolve list keys. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005166 *
Michal Vaskobb211122015-08-19 14:03:11 +02005167 * @param[in] list List to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005168 * @param[in] keys_str Keys node value.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005169 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005170 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005171 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005172static int
Radek Krejci48464ed2016-03-17 15:44:09 +01005173resolve_list_keys(struct lys_node_list *list, const char *keys_str)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005174{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005175 int i, len, rc;
Michal Vasko4f0dad02016-02-15 14:08:23 +01005176 const char *value;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005177
5178 for (i = 0; i < list->keys_size; ++i) {
5179 /* get the key name */
5180 if ((value = strpbrk(keys_str, " \t\n"))) {
5181 len = value - keys_str;
5182 while (isspace(value[0])) {
5183 value++;
5184 }
5185 } else {
5186 len = strlen(keys_str);
5187 }
5188
Radek Krejcic4283442016-04-22 09:19:27 +02005189 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 +02005190 if (rc) {
Michal Vasko7a55bea2016-05-02 14:51:20 +02005191 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, list, "list keys", keys_str);
5192 return EXIT_FAILURE;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005193 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005194
Radek Krejci48464ed2016-03-17 15:44:09 +01005195 if (check_key(list, i, keys_str, len)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005196 /* check_key logs */
5197 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005198 }
5199
Radek Krejcicf509982015-12-15 09:22:44 +01005200 /* check status */
Radek Krejcic6556022016-01-27 15:16:45 +01005201 if (lyp_check_status(list->flags, list->module, list->name,
Radek Krejci48464ed2016-03-17 15:44:09 +01005202 list->keys[i]->flags, list->keys[i]->module, list->keys[i]->name,
5203 (struct lys_node *)list->keys[i])) {
Radek Krejcicf509982015-12-15 09:22:44 +01005204 return -1;
5205 }
5206
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005207 /* prepare for next iteration */
5208 while (value && isspace(value[0])) {
5209 value++;
5210 }
5211 keys_str = value;
5212 }
5213
Michal Vaskof02e3742015-08-05 16:27:02 +02005214 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005215}
5216
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005217/**
Michal Vaskobf19d252015-10-08 15:39:17 +02005218 * @brief Resolve (check) all must conditions of \p node.
5219 * Logs directly.
5220 *
5221 * @param[in] node Data node with optional must statements.
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005222 * @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 +02005223 *
5224 * @return EXIT_SUCCESS on pass, EXIT_FAILURE on fail, -1 on error.
5225 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005226static int
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005227resolve_must(struct lyd_node *node, int inout_parent)
Michal Vaskof02e3742015-08-05 16:27:02 +02005228{
Michal Vaskobf19d252015-10-08 15:39:17 +02005229 uint8_t i, must_size;
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005230 struct lys_node *schema;
Michal Vaskobf19d252015-10-08 15:39:17 +02005231 struct lys_restr *must;
5232 struct lyxp_set set;
5233
5234 assert(node);
5235 memset(&set, 0, sizeof set);
5236
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005237 if (inout_parent) {
5238 for (schema = lys_parent(node->schema);
5239 schema && (schema->nodetype & (LYS_CHOICE | LYS_CASE | LYS_USES));
5240 schema = lys_parent(schema));
5241 if (!schema || !(schema->nodetype & (LYS_INPUT | LYS_OUTPUT))) {
5242 LOGINT;
5243 return -1;
5244 }
5245 must_size = ((struct lys_node_inout *)schema)->must_size;
5246 must = ((struct lys_node_inout *)schema)->must;
5247
5248 /* context node is the RPC/action */
5249 node = node->parent;
5250 if (!(node->schema->nodetype & (LYS_RPC | LYS_ACTION))) {
5251 LOGINT;
5252 return -1;
5253 }
5254 } else {
5255 switch (node->schema->nodetype) {
5256 case LYS_CONTAINER:
5257 must_size = ((struct lys_node_container *)node->schema)->must_size;
5258 must = ((struct lys_node_container *)node->schema)->must;
5259 break;
5260 case LYS_LEAF:
5261 must_size = ((struct lys_node_leaf *)node->schema)->must_size;
5262 must = ((struct lys_node_leaf *)node->schema)->must;
5263 break;
5264 case LYS_LEAFLIST:
5265 must_size = ((struct lys_node_leaflist *)node->schema)->must_size;
5266 must = ((struct lys_node_leaflist *)node->schema)->must;
5267 break;
5268 case LYS_LIST:
5269 must_size = ((struct lys_node_list *)node->schema)->must_size;
5270 must = ((struct lys_node_list *)node->schema)->must;
5271 break;
5272 case LYS_ANYXML:
5273 case LYS_ANYDATA:
5274 must_size = ((struct lys_node_anydata *)node->schema)->must_size;
5275 must = ((struct lys_node_anydata *)node->schema)->must;
5276 break;
5277 case LYS_NOTIF:
5278 must_size = ((struct lys_node_notif *)node->schema)->must_size;
5279 must = ((struct lys_node_notif *)node->schema)->must;
5280 break;
5281 default:
5282 must_size = 0;
5283 break;
5284 }
Michal Vaskobf19d252015-10-08 15:39:17 +02005285 }
5286
5287 for (i = 0; i < must_size; ++i) {
Michal Vaskoa59495d2016-08-22 09:18:58 +02005288 if (lyxp_eval(must[i].expr, node, LYXP_NODE_ELEM, &set, LYXP_MUST)) {
Michal Vaskobf19d252015-10-08 15:39:17 +02005289 return -1;
5290 }
5291
Michal Vasko944a5642016-03-21 11:48:58 +01005292 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, node, LYXP_MUST);
Michal Vaskobf19d252015-10-08 15:39:17 +02005293
Michal Vasko8146d4c2016-05-09 15:50:29 +02005294 if (!set.val.bool) {
Michal Vasko6ac68282016-04-11 10:56:47 +02005295 LOGVAL(LYE_NOMUST, LY_VLOG_LYD, node, must[i].expr);
5296 if (must[i].emsg) {
5297 LOGVAL(LYE_SPEC, LY_VLOG_LYD, node, must[i].emsg);
5298 }
5299 if (must[i].eapptag) {
5300 strncpy(((struct ly_err *)&ly_errno)->apptag, must[i].eapptag, LY_APPTAG_LEN - 1);
5301 }
Michal Vaskobf19d252015-10-08 15:39:17 +02005302 return 1;
5303 }
5304 }
5305
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005306 return EXIT_SUCCESS;
Michal Vaskof02e3742015-08-05 16:27:02 +02005307}
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005308
Michal Vaskobf19d252015-10-08 15:39:17 +02005309/**
Michal Vasko508a50d2016-09-07 14:50:33 +02005310 * @brief Resolve (find) when condition schema context node. Does not log.
5311 *
5312 * @param[in] schema Schema node with the when condition.
5313 * @param[out] ctx_snode When schema context node.
5314 * @param[out] ctx_snode_type Schema context node type.
5315 */
5316void
5317resolve_when_ctx_snode(const struct lys_node *schema, struct lys_node **ctx_snode, enum lyxp_node_type *ctx_snode_type)
5318{
5319 const struct lys_node *sparent;
5320
5321 /* find a not schema-only node */
5322 *ctx_snode_type = LYXP_NODE_ELEM;
5323 while (schema->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE | LYS_AUGMENT | LYS_INPUT | LYS_OUTPUT)) {
5324 if (schema->nodetype == LYS_AUGMENT) {
5325 sparent = ((struct lys_node_augment *)schema)->target;
5326 } else {
5327 sparent = schema->parent;
5328 }
5329 if (!sparent) {
5330 /* context node is the document root (fake root in our case) */
5331 if (schema->flags & LYS_CONFIG_W) {
5332 *ctx_snode_type = LYXP_NODE_ROOT_CONFIG;
5333 } else {
Michal Vaskob94a5e42016-09-08 14:01:56 +02005334 *ctx_snode_type = LYXP_NODE_ROOT;
Michal Vasko508a50d2016-09-07 14:50:33 +02005335 }
Michal Vasko2d2aec12016-09-08 11:42:50 +02005336 /* we need the first top-level sibling, but no uses or groupings */
Michal Vaskob94a5e42016-09-08 14:01:56 +02005337 schema = lys_getnext(NULL, NULL, lys_node_module(schema), 0);
Michal Vasko508a50d2016-09-07 14:50:33 +02005338 break;
5339 }
5340 schema = sparent;
5341 }
5342
5343 *ctx_snode = (struct lys_node *)schema;
5344}
5345
5346/**
Michal Vaskocf024702015-10-08 15:01:42 +02005347 * @brief Resolve (find) when condition context node. Does not log.
5348 *
5349 * @param[in] node Data node, whose conditional definition is being decided.
Michal Vasko508a50d2016-09-07 14:50:33 +02005350 * @param[in] schema Schema node with the when condition.
Michal Vaskoa59495d2016-08-22 09:18:58 +02005351 * @param[out] ctx_node Context node.
5352 * @param[out] ctx_node_type Context node type.
Michal Vaskocf024702015-10-08 15:01:42 +02005353 *
Michal Vaskoa59495d2016-08-22 09:18:58 +02005354 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vaskocf024702015-10-08 15:01:42 +02005355 */
Michal Vaskoa59495d2016-08-22 09:18:58 +02005356static int
5357resolve_when_ctx_node(struct lyd_node *node, struct lys_node *schema, struct lyd_node **ctx_node,
5358 enum lyxp_node_type *ctx_node_type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005359{
Michal Vaskocf024702015-10-08 15:01:42 +02005360 struct lyd_node *parent;
5361 struct lys_node *sparent;
Michal Vaskoa59495d2016-08-22 09:18:58 +02005362 enum lyxp_node_type node_type;
Michal Vaskocf024702015-10-08 15:01:42 +02005363 uint16_t i, data_depth, schema_depth;
5364
Michal Vasko508a50d2016-09-07 14:50:33 +02005365 resolve_when_ctx_snode(schema, &schema, &node_type);
Michal Vaskocf024702015-10-08 15:01:42 +02005366
Michal Vaskofe989752016-09-08 08:47:26 +02005367 if (node_type == LYXP_NODE_ELEM) {
5368 /* standard element context node */
5369 for (parent = node, data_depth = 0; parent; parent = parent->parent, ++data_depth);
5370 for (sparent = schema, schema_depth = 0;
5371 sparent;
5372 sparent = (sparent->nodetype == LYS_AUGMENT ? ((struct lys_node_augment *)sparent)->target : sparent->parent)) {
5373 if (sparent->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_ANYDATA | LYS_NOTIF | LYS_RPC)) {
5374 ++schema_depth;
5375 }
Michal Vaskocf024702015-10-08 15:01:42 +02005376 }
Michal Vaskofe989752016-09-08 08:47:26 +02005377 if (data_depth < schema_depth) {
5378 return -1;
5379 }
Michal Vaskocf024702015-10-08 15:01:42 +02005380
Michal Vasko956e8542016-08-26 09:43:35 +02005381 /* find the corresponding data node */
5382 for (i = 0; i < data_depth - schema_depth; ++i) {
5383 node = node->parent;
5384 }
Michal Vaskoa59495d2016-08-22 09:18:58 +02005385 if (node->schema != schema) {
5386 return -1;
5387 }
Michal Vaskofe989752016-09-08 08:47:26 +02005388 } else {
5389 /* root context node */
5390 while (node->parent) {
5391 node = node->parent;
5392 }
5393 while (node->prev->next) {
5394 node = node->prev;
5395 }
Michal Vaskocf024702015-10-08 15:01:42 +02005396 }
5397
Michal Vaskoa59495d2016-08-22 09:18:58 +02005398 *ctx_node = node;
5399 *ctx_node_type = node_type;
5400 return EXIT_SUCCESS;
Michal Vaskocf024702015-10-08 15:01:42 +02005401}
5402
Michal Vasko76c3bd32016-08-24 16:02:52 +02005403/**
5404 * @brief Temporarily unlink nodes as per YANG 1.1 RFC section 7.21.5 for when XPath evaluation.
5405 * The context nodes is adjusted if needed.
5406 *
5407 * @param[in] snode Schema node, whose children instances need to be unlinked.
5408 * @param[in,out] node Data siblings where to look for the children of \p snode. If it is unlinked,
5409 * it is moved to point to another sibling still in the original tree.
5410 * @param[in,out] ctx_node When context node, adjusted if needed.
5411 * @param[in] ctx_node_type Context node type, just for information to detect invalid situations.
5412 * @param[out] unlinked_nodes Unlinked siblings. Can be safely appended to \p node afterwards.
5413 * Ordering may change, but there will be no semantic change.
5414 *
5415 * @return EXIT_SUCCESS on success, -1 on error.
5416 */
5417static int
5418resolve_when_unlink_nodes(struct lys_node *snode, struct lyd_node **node, struct lyd_node **ctx_node,
5419 enum lyxp_node_type ctx_node_type, struct lyd_node **unlinked_nodes)
5420{
5421 struct lyd_node *next, *elem;
5422
5423 switch (snode->nodetype) {
5424 case LYS_AUGMENT:
5425 case LYS_USES:
5426 case LYS_CHOICE:
5427 case LYS_CASE:
5428 LY_TREE_FOR(snode->child, snode) {
5429 if (resolve_when_unlink_nodes(snode, node, ctx_node, ctx_node_type, unlinked_nodes)) {
5430 return -1;
5431 }
5432 }
5433 break;
5434 case LYS_CONTAINER:
5435 case LYS_LIST:
5436 case LYS_LEAF:
5437 case LYS_LEAFLIST:
5438 case LYS_ANYXML:
5439 case LYS_ANYDATA:
5440 LY_TREE_FOR_SAFE(lyd_first_sibling(*node), next, elem) {
5441 if (elem->schema == snode) {
5442
5443 if (elem == *ctx_node) {
5444 /* We are going to unlink our context node! This normally cannot happen,
5445 * but we use normal top-level data nodes for faking a document root node,
5446 * so if this is the context node, we just use the next top-level node.
5447 * Additionally, it can even happen that there are no top-level data nodes left,
5448 * all were unlinked, so in this case we pass NULL as the context node/data tree,
5449 * lyxp_eval() can handle this special situation.
5450 */
5451 if (ctx_node_type == LYXP_NODE_ELEM) {
5452 LOGINT;
5453 return -1;
5454 }
5455
5456 if (elem->prev == elem) {
5457 /* unlinking last top-level element, use an empty data tree */
5458 *ctx_node = NULL;
5459 } else {
5460 /* in this case just use the previous/last top-level data node */
5461 *ctx_node = elem->prev;
5462 }
5463 } else if (elem == *node) {
5464 /* We are going to unlink the currently processed node. This does not matter that
5465 * much, but we would lose access to the original data tree, so just move our
5466 * pointer somewhere still inside it.
5467 */
5468 if ((*node)->prev != *node) {
5469 *node = (*node)->prev;
5470 } else {
5471 /* the processed node with sibings were all unlinked, oh well */
5472 *node = NULL;
5473 }
5474 }
5475
5476 /* temporarily unlink the node */
5477 lyd_unlink(elem);
5478 if (*unlinked_nodes) {
5479 if (lyd_insert_after(*unlinked_nodes, elem)) {
5480 LOGINT;
5481 return -1;
5482 }
5483 } else {
5484 *unlinked_nodes = elem;
5485 }
5486
5487 if (snode->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_ANYDATA)) {
5488 /* there can be only one instance */
5489 break;
5490 }
5491 }
5492 }
5493 break;
5494 default:
5495 LOGINT;
5496 return -1;
5497 }
5498
5499 return EXIT_SUCCESS;
5500}
5501
5502/**
5503 * @brief Relink the unlinked nodes back.
5504 *
5505 * @param[in] node Data node to link the nodes back to. It can actually be the adjusted context node,
5506 * we simply need a sibling from the original data tree.
5507 * @param[in] unlinked_nodes Unlinked nodes to relink to \p node.
5508 * @param[in] ctx_node_type Context node type to distinguish between \p node being the parent
5509 * or the sibling of \p unlinked_nodes.
5510 *
5511 * @return EXIT_SUCCESS on success, -1 on error.
5512 */
5513static int
5514resolve_when_relink_nodes(struct lyd_node *node, struct lyd_node *unlinked_nodes, enum lyxp_node_type ctx_node_type)
5515{
5516 struct lyd_node *elem;
5517
5518 LY_TREE_FOR_SAFE(unlinked_nodes, unlinked_nodes, elem) {
5519 if (ctx_node_type == LYXP_NODE_ELEM) {
5520 if (lyd_insert(node, elem)) {
5521 return -1;
5522 }
5523 } else {
5524 if (lyd_insert_after(node, elem)) {
5525 return -1;
5526 }
5527 }
5528 }
5529
5530 return EXIT_SUCCESS;
5531}
5532
Radek Krejci03b71f72016-03-16 11:10:09 +01005533int
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005534resolve_applies_must(const struct lyd_node *node)
Radek Krejci01696bf2016-03-18 13:19:36 +01005535{
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005536 int ret = 0;
5537 uint8_t must_size;
5538 struct lys_node *schema, *iter;
Radek Krejci46165822016-08-26 14:06:27 +02005539
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005540 assert(node);
5541
5542 schema = node->schema;
5543
5544 /* their own must */
Radek Krejci46165822016-08-26 14:06:27 +02005545 switch (schema->nodetype) {
Radek Krejci01696bf2016-03-18 13:19:36 +01005546 case LYS_CONTAINER:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005547 must_size = ((struct lys_node_container *)schema)->must_size;
5548 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005549 case LYS_LEAF:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005550 must_size = ((struct lys_node_leaf *)schema)->must_size;
5551 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005552 case LYS_LEAFLIST:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005553 must_size = ((struct lys_node_leaflist *)schema)->must_size;
5554 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005555 case LYS_LIST:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005556 must_size = ((struct lys_node_list *)schema)->must_size;
5557 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005558 case LYS_ANYXML:
Radek Krejcibf2abff2016-08-23 15:51:52 +02005559 case LYS_ANYDATA:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005560 must_size = ((struct lys_node_anydata *)schema)->must_size;
5561 break;
5562 case LYS_NOTIF:
5563 must_size = ((struct lys_node_notif *)schema)->must_size;
5564 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005565 default:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005566 must_size = 0;
5567 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005568 }
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005569
5570 if (must_size) {
5571 ++ret;
5572 }
5573
5574 /* schema may be a direct data child of input/output with must (but it must be first, it needs to be evaluated only once) */
5575 if (!node->prev->next) {
5576 for (iter = lys_parent(schema); iter && (iter->nodetype & (LYS_CHOICE | LYS_CASE | LYS_USES)); iter = lys_parent(iter));
5577 if (iter && (iter->nodetype & (LYS_INPUT | LYS_OUTPUT))) {
5578 ret += 0x2;
5579 }
5580 }
5581
5582 return ret;
Radek Krejci01696bf2016-03-18 13:19:36 +01005583}
5584
5585int
Radek Krejci46165822016-08-26 14:06:27 +02005586resolve_applies_when(const struct lys_node *schema, int mode, const struct lys_node *stop)
Radek Krejci03b71f72016-03-16 11:10:09 +01005587{
Radek Krejci46165822016-08-26 14:06:27 +02005588 const struct lys_node *parent;
Radek Krejci03b71f72016-03-16 11:10:09 +01005589
Radek Krejci46165822016-08-26 14:06:27 +02005590 assert(schema);
Radek Krejci03b71f72016-03-16 11:10:09 +01005591
Radek Krejci46165822016-08-26 14:06:27 +02005592 if (!(schema->nodetype & (LYS_NOTIF | LYS_RPC)) && (((struct lys_node_container *)schema)->when)) {
Radek Krejci03b71f72016-03-16 11:10:09 +01005593 return 1;
5594 }
5595
Radek Krejci46165822016-08-26 14:06:27 +02005596 parent = schema;
Radek Krejci03b71f72016-03-16 11:10:09 +01005597 goto check_augment;
5598
Radek Krejci46165822016-08-26 14:06:27 +02005599 while (parent) {
5600 /* stop conditions */
5601 if (!mode) {
5602 /* stop on node that can be instantiated in data tree */
5603 if (!(parent->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE))) {
5604 break;
5605 }
5606 } else {
5607 /* stop on the specified node */
5608 if (parent == stop) {
5609 break;
5610 }
5611 }
5612
5613 if (((const struct lys_node_uses *)parent)->when) {
Radek Krejci03b71f72016-03-16 11:10:09 +01005614 return 1;
5615 }
5616check_augment:
5617
5618 if ((parent->parent && (parent->parent->nodetype == LYS_AUGMENT) &&
Radek Krejci46165822016-08-26 14:06:27 +02005619 (((const struct lys_node_augment *)parent->parent)->when))) {
Michal Vaskoe3655562016-08-24 15:56:17 +02005620 return 1;
Radek Krejci03b71f72016-03-16 11:10:09 +01005621 }
5622 parent = lys_parent(parent);
5623 }
5624
5625 return 0;
5626}
5627
Michal Vaskocf024702015-10-08 15:01:42 +02005628/**
5629 * @brief Resolve (check) all when conditions relevant for \p node.
5630 * Logs directly.
5631 *
5632 * @param[in] node Data node, whose conditional reference, if such, is being decided.
Michal Vaskocf024702015-10-08 15:01:42 +02005633 *
Radek Krejci03b71f72016-03-16 11:10:09 +01005634 * @return
5635 * -1 - error, ly_errno is set
5636 * 0 - true "when" statement
Radek Krejci46165822016-08-26 14:06:27 +02005637 * 0, ly_vecode = LYVE_NOWHEN - false "when" statement
Radek Krejci03b71f72016-03-16 11:10:09 +01005638 * 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 +02005639 */
Radek Krejci46165822016-08-26 14:06:27 +02005640int
5641resolve_when(struct lyd_node *node, int *result)
Michal Vaskocf024702015-10-08 15:01:42 +02005642{
Michal Vasko76c3bd32016-08-24 16:02:52 +02005643 struct lyd_node *ctx_node = NULL, *unlinked_nodes, *tmp_node;
Michal Vasko90fc2a32016-08-24 15:58:58 +02005644 struct lys_node *sparent;
Michal Vaskocf024702015-10-08 15:01:42 +02005645 struct lyxp_set set;
Michal Vaskoa59495d2016-08-22 09:18:58 +02005646 enum lyxp_node_type ctx_node_type;
Radek Krejci51093642016-03-29 10:14:59 +02005647 int rc = 0;
Michal Vaskocf024702015-10-08 15:01:42 +02005648
5649 assert(node);
5650 memset(&set, 0, sizeof set);
5651
5652 if (!(node->schema->nodetype & (LYS_NOTIF | LYS_RPC)) && (((struct lys_node_container *)node->schema)->when)) {
Michal Vasko76c3bd32016-08-24 16:02:52 +02005653 /* make the node dummy for the evaluation */
5654 node->validity |= LYD_VAL_INUSE;
Michal Vaskoa59495d2016-08-22 09:18:58 +02005655 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 +02005656 node->validity &= ~LYD_VAL_INUSE;
Radek Krejci03b71f72016-03-16 11:10:09 +01005657 if (rc) {
5658 if (rc == 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01005659 LOGVAL(LYE_INWHEN, LY_VLOG_LYD, node, ((struct lys_node_container *)node->schema)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01005660 }
Radek Krejci51093642016-03-29 10:14:59 +02005661 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005662 }
5663
Radek Krejci03b71f72016-03-16 11:10:09 +01005664 /* set boolean result of the condition */
Michal Vasko944a5642016-03-21 11:48:58 +01005665 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, node, LYXP_WHEN);
Michal Vasko8146d4c2016-05-09 15:50:29 +02005666 if (!set.val.bool) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02005667 LOGVAL(LYE_NOWHEN, LY_VLOG_LYD, node, ((struct lys_node_container *)node->schema)->when->cond);
Radek Krejci0b7704f2016-03-18 12:16:14 +01005668 node->when_status |= LYD_WHEN_FALSE;
Radek Krejci51093642016-03-29 10:14:59 +02005669 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005670 }
Radek Krejci51093642016-03-29 10:14:59 +02005671
5672 /* free xpath set content */
5673 lyxp_set_cast(&set, LYXP_SET_EMPTY, node, 0);
Michal Vaskocf024702015-10-08 15:01:42 +02005674 }
5675
Michal Vasko90fc2a32016-08-24 15:58:58 +02005676 sparent = node->schema;
Michal Vaskocf024702015-10-08 15:01:42 +02005677 goto check_augment;
5678
5679 /* check when in every schema node that affects node */
Michal Vasko90fc2a32016-08-24 15:58:58 +02005680 while (sparent && (sparent->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE))) {
5681 if (((struct lys_node_uses *)sparent)->when) {
Michal Vaskocf024702015-10-08 15:01:42 +02005682 if (!ctx_node) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02005683 rc = resolve_when_ctx_node(node, sparent, &ctx_node, &ctx_node_type);
Michal Vaskoa59495d2016-08-22 09:18:58 +02005684 if (rc) {
Michal Vaskocf024702015-10-08 15:01:42 +02005685 LOGINT;
Radek Krejci51093642016-03-29 10:14:59 +02005686 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005687 }
5688 }
Michal Vasko76c3bd32016-08-24 16:02:52 +02005689
5690 unlinked_nodes = NULL;
5691 /* we do not want our node pointer to change */
5692 tmp_node = node;
5693 rc = resolve_when_unlink_nodes(sparent, &tmp_node, &ctx_node, ctx_node_type, &unlinked_nodes);
5694 if (rc) {
5695 goto cleanup;
5696 }
5697
5698 rc = lyxp_eval(((struct lys_node_uses *)sparent)->when->cond, ctx_node, ctx_node_type, &set, LYXP_WHEN);
5699
5700 if (unlinked_nodes && ctx_node) {
5701 if (resolve_when_relink_nodes(ctx_node, unlinked_nodes, ctx_node_type)) {
5702 rc = -1;
5703 goto cleanup;
5704 }
5705 }
5706
Radek Krejci03b71f72016-03-16 11:10:09 +01005707 if (rc) {
5708 if (rc == 1) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02005709 LOGVAL(LYE_INWHEN, LY_VLOG_LYD, node, ((struct lys_node_uses *)sparent)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01005710 }
Radek Krejci51093642016-03-29 10:14:59 +02005711 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005712 }
5713
Michal Vasko944a5642016-03-21 11:48:58 +01005714 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, ctx_node, LYXP_WHEN);
Michal Vasko8146d4c2016-05-09 15:50:29 +02005715 if (!set.val.bool) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02005716 LOGVAL(LYE_NOWHEN, LY_VLOG_LYD, node, ((struct lys_node_uses *)sparent)->when->cond);
Radek Krejci0b7704f2016-03-18 12:16:14 +01005717 node->when_status |= LYD_WHEN_FALSE;
Radek Krejci51093642016-03-29 10:14:59 +02005718 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005719 }
Radek Krejci51093642016-03-29 10:14:59 +02005720
5721 /* free xpath set content */
5722 lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node, 0);
Michal Vaskocf024702015-10-08 15:01:42 +02005723 }
5724
5725check_augment:
Michal Vasko90fc2a32016-08-24 15:58:58 +02005726 if ((sparent->parent && (sparent->parent->nodetype == LYS_AUGMENT) && (((struct lys_node_augment *)sparent->parent)->when))) {
Michal Vaskocf024702015-10-08 15:01:42 +02005727 if (!ctx_node) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02005728 rc = resolve_when_ctx_node(node, sparent->parent, &ctx_node, &ctx_node_type);
Michal Vaskoa59495d2016-08-22 09:18:58 +02005729 if (rc) {
Michal Vaskocf024702015-10-08 15:01:42 +02005730 LOGINT;
Radek Krejci51093642016-03-29 10:14:59 +02005731 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005732 }
5733 }
Michal Vasko76c3bd32016-08-24 16:02:52 +02005734
5735 unlinked_nodes = NULL;
5736 tmp_node = node;
5737 rc = resolve_when_unlink_nodes(sparent->parent, &tmp_node, &ctx_node, ctx_node_type, &unlinked_nodes);
5738 if (rc) {
5739 goto cleanup;
5740 }
5741
5742 rc = lyxp_eval(((struct lys_node_augment *)sparent->parent)->when->cond, ctx_node, ctx_node_type, &set, LYXP_WHEN);
5743
5744 /* reconnect nodes, if ctx_node is NULL then all the nodes were unlinked, but linked together,
5745 * so the tree did not actually change and there is nothing for us to do
5746 */
5747 if (unlinked_nodes && ctx_node) {
5748 if (resolve_when_relink_nodes(ctx_node, unlinked_nodes, ctx_node_type)) {
5749 rc = -1;
5750 goto cleanup;
5751 }
5752 }
5753
Radek Krejci03b71f72016-03-16 11:10:09 +01005754 if (rc) {
5755 if (rc == 1) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02005756 LOGVAL(LYE_INWHEN, LY_VLOG_LYD, node, ((struct lys_node_augment *)sparent->parent)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01005757 }
Radek Krejci51093642016-03-29 10:14:59 +02005758 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005759 }
5760
Michal Vasko944a5642016-03-21 11:48:58 +01005761 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, ctx_node, LYXP_WHEN);
Michal Vaskocf024702015-10-08 15:01:42 +02005762
Michal Vasko8146d4c2016-05-09 15:50:29 +02005763 if (!set.val.bool) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02005764 LOGVAL(LYE_NOWHEN, LY_VLOG_LYD, node, ((struct lys_node_augment *)sparent->parent)->when->cond);
Radek Krejci0b7704f2016-03-18 12:16:14 +01005765 node->when_status |= LYD_WHEN_FALSE;
Radek Krejci51093642016-03-29 10:14:59 +02005766 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005767 }
Radek Krejci51093642016-03-29 10:14:59 +02005768
5769 /* free xpath set content */
5770 lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node, 0);
Michal Vaskocf024702015-10-08 15:01:42 +02005771 }
5772
Michal Vasko90fc2a32016-08-24 15:58:58 +02005773 sparent = lys_parent(sparent);
Michal Vaskocf024702015-10-08 15:01:42 +02005774 }
5775
Radek Krejci0b7704f2016-03-18 12:16:14 +01005776 node->when_status |= LYD_WHEN_TRUE;
Radek Krejci03b71f72016-03-16 11:10:09 +01005777
Radek Krejci51093642016-03-29 10:14:59 +02005778cleanup:
Radek Krejci51093642016-03-29 10:14:59 +02005779 /* free xpath set content */
5780 lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node ? ctx_node : node, 0);
5781
Radek Krejci46165822016-08-26 14:06:27 +02005782 if (result) {
5783 if (node->when_status & LYD_WHEN_TRUE) {
5784 *result = 1;
5785 } else {
5786 *result = 0;
5787 }
5788 }
5789
Radek Krejci51093642016-03-29 10:14:59 +02005790 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005791}
5792
Radek Krejcicbb473e2016-09-16 14:48:32 +02005793static int
5794check_leafref_features(struct lys_type *type)
5795{
5796 struct lys_node *iter;
5797 struct ly_set *src_parents, *trg_parents, *features;
5798 unsigned int i, j, size, x;
5799 int ret = EXIT_SUCCESS;
5800
5801 assert(type->parent);
5802
5803 src_parents = ly_set_new();
5804 trg_parents = ly_set_new();
5805 features = ly_set_new();
5806
5807 /* get parents chain of source (leafref) */
5808 for (iter = (struct lys_node *)type->parent; iter; iter = iter->parent) {
5809 if (iter->nodetype & (LYS_INPUT | LYS_OUTPUT)) {
5810 continue;
5811 }
5812 ly_set_add(src_parents, iter, LY_SET_OPT_USEASLIST);
5813 }
5814 /* get parents chain of target */
5815 for (iter = (struct lys_node *)type->info.lref.target; iter; iter = iter->parent) {
5816 if (iter->nodetype & (LYS_INPUT | LYS_OUTPUT)) {
5817 continue;
5818 }
5819 ly_set_add(trg_parents, iter, LY_SET_OPT_USEASLIST);
5820 }
5821
5822 /* compare the features used in if-feature statements in the rest of both
5823 * chains of parents. The set of features used for target must be a subset
5824 * of features used for the leafref. This is not a perfect, we should compare
5825 * the truth tables but it could require too much resources, so we simplify that */
5826 for (i = 0; i < src_parents->number; i++) {
5827 iter = src_parents->set.s[i]; /* shortcut */
5828 if (!iter->iffeature_size) {
5829 continue;
5830 }
5831 for (j = 0; j < iter->iffeature_size; j++) {
5832 resolve_iffeature_getsizes(&iter->iffeature[j], NULL, &size);
5833 for (; size; size--) {
5834 if (!iter->iffeature[j].features[size - 1]) {
5835 /* not yet resolved feature, postpone this check */
5836 ret = EXIT_FAILURE;
5837 goto cleanup;
5838 }
5839 ly_set_add(features, iter->iffeature[j].features[size - 1], 0);
5840 }
5841 }
5842 }
5843 x = features->number;
5844 for (i = 0; i < trg_parents->number; i++) {
5845 iter = trg_parents->set.s[i]; /* shortcut */
5846 if (!iter->iffeature_size) {
5847 continue;
5848 }
5849 for (j = 0; j < iter->iffeature_size; j++) {
5850 resolve_iffeature_getsizes(&iter->iffeature[j], NULL, &size);
5851 for (; size; size--) {
5852 if (!iter->iffeature[j].features[size - 1]) {
5853 /* not yet resolved feature, postpone this check */
5854 ret = EXIT_FAILURE;
5855 goto cleanup;
5856 }
5857 if ((unsigned int)ly_set_add(features, iter->iffeature[j].features[size - 1], 0) >= x) {
5858 /* the feature is not present in features set of target's parents chain */
5859 LOGVAL(LYE_NORESOLV, LY_VLOG_LYS, type->parent, "leafref", type->info.lref.path);
5860 LOGVAL(LYE_SPEC, LY_VLOG_LYS, type->parent,
5861 "Leafref is not conditional based on \"%s\" feature as its target.",
5862 iter->iffeature[j].features[size - 1]->name);
5863 ret = -1;
5864 goto cleanup;
5865 }
5866 }
5867 }
5868 }
5869
5870cleanup:
5871 ly_set_free(features);
5872 ly_set_free(src_parents);
5873 ly_set_free(trg_parents);
5874
5875 return ret;
5876}
5877
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005878/**
Michal Vaskobb211122015-08-19 14:03:11 +02005879 * @brief Resolve a single unres schema item. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005880 *
5881 * @param[in] mod Main module.
5882 * @param[in] item Item to resolve. Type determined by \p type.
5883 * @param[in] type Type of the unresolved item.
5884 * @param[in] str_snode String, a schema node, or NULL.
Michal Vaskobb211122015-08-19 14:03:11 +02005885 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005886 *
5887 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
5888 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005889static int
Michal Vasko0bd29d12015-08-19 11:45:49 +02005890resolve_unres_schema_item(struct lys_module *mod, void *item, enum UNRES_ITEM type, void *str_snode,
Radek Krejci48464ed2016-03-17 15:44:09 +01005891 struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005892{
Michal Vaskoc5c26b02016-06-29 11:10:29 +02005893 /* has_str - whether the str_snode is a string in a dictionary that needs to be freed */
Radek Krejcic79c6b12016-07-26 15:11:49 +02005894 int rc = -1, has_str = 0, tpdf_flag = 0, i, k;
5895 unsigned int j;
Radek Krejcic13db382016-08-16 10:52:42 +02005896 struct lys_node *node, *par_grp;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02005897 const char *expr;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02005898
Radek Krejcic79c6b12016-07-26 15:11:49 +02005899 struct ly_set *refs, *procs;
5900 struct lys_feature *ref, *feat;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02005901 struct lys_ident *ident;
5902 struct lys_type *stype;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02005903 struct lys_node_choice *choic;
Michal Vasko88c29542015-11-27 14:57:53 +01005904 struct lyxml_elem *yin;
Pavol Vicana0e4e672016-02-24 12:20:04 +01005905 struct yang_type *yang;
Radek Krejcid09d1a52016-08-11 14:05:45 +02005906 struct unres_list_uniq *unique_info;
Radek Krejcicbb473e2016-09-16 14:48:32 +02005907 struct unres_iffeat_data *iff_data;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005908
5909 switch (type) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005910 case UNRES_IDENT:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02005911 expr = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01005912 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02005913 ident = item;
5914
Radek Krejci018f1f52016-08-03 16:01:20 +02005915 rc = resolve_base_ident(mod, ident, expr, "identity", NULL, unres);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005916 break;
5917 case UNRES_TYPE_IDENTREF:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02005918 expr = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01005919 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02005920 stype = item;
5921
Radek Krejci018f1f52016-08-03 16:01:20 +02005922 rc = resolve_base_ident(mod, NULL, expr, "type", stype, unres);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005923 break;
5924 case UNRES_TYPE_LEAFREF:
Michal Vasko563ef092015-09-04 13:17:23 +02005925 node = str_snode;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02005926 stype = item;
5927
Radek Krejci2f12f852016-01-08 12:59:57 +01005928 /* HACK - when there is no parent, we are in top level typedef and in that
5929 * case, the path has to contain absolute path, so we let the resolve_path_arg_schema()
5930 * know it via tpdf_flag */
5931 if (!node) {
Radek Krejci4f78b532016-02-17 13:43:00 +01005932 tpdf_flag = 1;
Radek Krejci2f12f852016-01-08 12:59:57 +01005933 node = (struct lys_node *)stype->parent;
5934 }
5935
Radek Krejci27fe55e2016-09-13 17:13:35 +02005936 if (!lys_node_module(node)->implemented) {
5937 /* not implemented module, don't bother with resolving the leafref
5938 * if the module is set to be implemented, tha path will be resolved then */
5939 rc = 0;
5940 break;
5941 }
Radek Krejci48464ed2016-03-17 15:44:09 +01005942 rc = resolve_path_arg_schema(stype->info.lref.path, node, tpdf_flag,
Michal Vasko1e62a092015-12-01 12:27:20 +01005943 (const struct lys_node **)&stype->info.lref.target);
Michal Vasko01c6fd22016-05-20 11:43:05 +02005944 if (!tpdf_flag && !rc) {
5945 assert(stype->info.lref.target);
Radek Krejcicbb473e2016-09-16 14:48:32 +02005946 /* check if leafref and its target are under a common if-features */
5947 rc = check_leafref_features(stype);
5948 if (rc) {
5949 break;
5950 }
5951
Radek Krejci46c4cd72016-01-21 15:13:52 +01005952 /* store the backlink from leafref target */
Michal Vasko01c6fd22016-05-20 11:43:05 +02005953 if (lys_leaf_add_leafref_target(stype->info.lref.target, (struct lys_node *)stype->parent)) {
5954 rc = -1;
Radek Krejci46c4cd72016-01-21 15:13:52 +01005955 }
Radek Krejci46c4cd72016-01-21 15:13:52 +01005956 }
5957
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005958 break;
Radek Krejci3a5501d2016-07-18 22:03:34 +02005959 case UNRES_TYPE_DER_TPDF:
5960 tpdf_flag = 1;
5961 /* no break */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005962 case UNRES_TYPE_DER:
Michal Vasko88c29542015-11-27 14:57:53 +01005963 /* parent */
5964 node = str_snode;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02005965 stype = item;
5966
Michal Vasko88c29542015-11-27 14:57:53 +01005967 /* HACK type->der is temporarily unparsed type statement */
5968 yin = (struct lyxml_elem *)stype->der;
5969 stype->der = NULL;
5970
Pavol Vicana0e4e672016-02-24 12:20:04 +01005971 if (yin->flags & LY_YANG_STRUCTURE_FLAG) {
5972 yang = (struct yang_type *)yin;
Radek Krejci3a5501d2016-07-18 22:03:34 +02005973 rc = yang_check_type(mod, node, yang, tpdf_flag, unres);
Pavol Vicana0e4e672016-02-24 12:20:04 +01005974
5975 if (rc) {
Pavol Vican8bd72e42016-08-29 09:53:05 +02005976 /* may try again later */
5977 stype->der = (struct lys_tpdf *)yang;
Pavol Vicand01d8ae2016-03-01 10:45:59 +01005978 } else {
5979 /* we need to always be able to free this, it's safe only in this case */
Pavol Vican5f0316a2016-04-05 21:21:11 +02005980 lydict_remove(mod->ctx, yang->name);
Pavol Vicand01d8ae2016-03-01 10:45:59 +01005981 free(yang);
Pavol Vicana0e4e672016-02-24 12:20:04 +01005982 }
5983
Michal Vasko88c29542015-11-27 14:57:53 +01005984 } else {
Radek Krejci3a5501d2016-07-18 22:03:34 +02005985 rc = fill_yin_type(mod, node, yin, stype, tpdf_flag, unres);
Pavol Vicana0e4e672016-02-24 12:20:04 +01005986 if (!rc) {
5987 /* we need to always be able to free this, it's safe only in this case */
5988 lyxml_free(mod->ctx, yin);
5989 } else {
5990 /* may try again later, put all back how it was */
5991 stype->der = (struct lys_tpdf *)yin;
5992 }
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02005993 }
Radek Krejcic13db382016-08-16 10:52:42 +02005994 if (rc == EXIT_SUCCESS) {
Radek Krejci2c2fce82016-08-01 13:52:26 +02005995 /* it does not make sense to have leaf-list of empty type */
5996 if (!tpdf_flag && node->nodetype == LYS_LEAFLIST && stype->base == LY_TYPE_EMPTY) {
5997 LOGWRN("The leaf-list \"%s\" is of \"empty\" type, which does not make sense.", node->name);
5998 }
Radek Krejci9b6aad22016-09-20 15:55:51 +02005999 } else if (rc == EXIT_FAILURE && stype->base != LY_TYPE_ERR) {
Radek Krejcic13db382016-08-16 10:52:42 +02006000 /* forward reference - in case the type is in grouping, we have to make the grouping unusable
6001 * by uses statement until the type is resolved. We do that the same way as uses statements inside
6002 * grouping - the grouping's nacm member (not used un grouping) is used to increase the number of
6003 * 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 +02006004 * 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 +02006005 * of the type's base member. */
6006 for (par_grp = node; par_grp && (par_grp->nodetype != LYS_GROUPING); par_grp = lys_parent(par_grp));
6007 if (par_grp) {
6008 ((struct lys_node_grp *)par_grp)->nacm++;
Radek Krejci9b6aad22016-09-20 15:55:51 +02006009 stype->base = LY_TYPE_ERR;
Radek Krejcic13db382016-08-16 10:52:42 +02006010 }
Radek Krejci2c2fce82016-08-01 13:52:26 +02006011 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006012 break;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006013 case UNRES_IFFEAT:
Radek Krejcicbb473e2016-09-16 14:48:32 +02006014 iff_data = str_snode;
6015 rc = resolve_feature(iff_data->fname, strlen(iff_data->fname), iff_data->node, item);
Radek Krejci9ff0a922016-07-14 13:08:05 +02006016 if (!rc) {
6017 /* success */
Radek Krejcicbb473e2016-09-16 14:48:32 +02006018 lydict_remove(mod->ctx, iff_data->fname);
6019 free(iff_data);
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006020 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006021 break;
Radek Krejcic79c6b12016-07-26 15:11:49 +02006022 case UNRES_FEATURE:
6023 feat = (struct lys_feature *)item;
6024
6025 if (feat->iffeature_size) {
6026 refs = ly_set_new();
6027 procs = ly_set_new();
6028 ly_set_add(procs, feat, 0);
6029
6030 while (procs->number) {
6031 ref = procs->set.g[procs->number - 1];
6032 ly_set_rm_index(procs, procs->number - 1);
6033
6034 for (i = 0; i < ref->iffeature_size; i++) {
6035 resolve_iffeature_getsizes(&ref->iffeature[i], NULL, &j);
6036 for (; j > 0 ; j--) {
Radek Krejcicbb473e2016-09-16 14:48:32 +02006037 if (ref->iffeature[i].features[j - 1]) {
Radek Krejcic79c6b12016-07-26 15:11:49 +02006038 if (ref->iffeature[i].features[j - 1] == feat) {
6039 LOGVAL(LYE_CIRC_FEATURES, LY_VLOG_NONE, NULL, feat->name);
6040 goto featurecheckdone;
6041 }
6042
6043 if (ref->iffeature[i].features[j - 1]->iffeature_size) {
6044 k = refs->number;
6045 if (ly_set_add(refs, ref->iffeature[i].features[j - 1], 0) == k) {
6046 /* not yet seen feature, add it for processing */
6047 ly_set_add(procs, ref->iffeature[i].features[j - 1], 0);
6048 }
6049 }
6050 } else {
6051 /* forward reference */
6052 rc = EXIT_FAILURE;
6053 goto featurecheckdone;
6054 }
6055 }
6056
6057 }
6058 }
6059 rc = EXIT_SUCCESS;
6060
6061featurecheckdone:
6062 ly_set_free(refs);
6063 ly_set_free(procs);
6064 }
6065
6066 break;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006067 case UNRES_USES:
Radek Krejci48464ed2016-03-17 15:44:09 +01006068 rc = resolve_unres_schema_uses(item, unres);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006069 break;
6070 case UNRES_TYPE_DFLT:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006071 expr = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01006072 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006073 stype = item;
6074
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006075 rc = check_default(stype, expr, mod);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006076 break;
6077 case UNRES_CHOICE_DFLT:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006078 expr = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01006079 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006080 choic = item;
6081
Radek Krejcie00d2312016-08-12 15:27:49 +02006082 if (!choic->dflt) {
6083 choic->dflt = resolve_choice_dflt(choic, expr);
6084 }
Michal Vasko7955b362015-09-04 14:18:15 +02006085 if (choic->dflt) {
Radek Krejcie00d2312016-08-12 15:27:49 +02006086 rc = lyp_check_mandatory_choice((struct lys_node *)choic);
Michal Vasko7955b362015-09-04 14:18:15 +02006087 } else {
6088 rc = EXIT_FAILURE;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006089 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006090 break;
6091 case UNRES_LIST_KEYS:
Radek Krejci4f78b532016-02-17 13:43:00 +01006092 has_str = 1;
Radek Krejci48464ed2016-03-17 15:44:09 +01006093 rc = resolve_list_keys(item, str_snode);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006094 break;
6095 case UNRES_LIST_UNIQ:
Radek Krejcid09d1a52016-08-11 14:05:45 +02006096 unique_info = (struct unres_list_uniq *)item;
6097 rc = resolve_unique(unique_info->list, unique_info->expr, unique_info->trg_type);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006098 break;
Michal Vasko7178e692016-02-12 15:58:05 +01006099 case UNRES_AUGMENT:
Radek Krejci48464ed2016-03-17 15:44:09 +01006100 rc = resolve_augment(item, NULL);
Michal Vasko7178e692016-02-12 15:58:05 +01006101 break;
Michal Vasko508a50d2016-09-07 14:50:33 +02006102 case UNRES_XPATH:
6103 node = (struct lys_node *)item;
Michal Vasko9e635ac2016-10-17 11:44:09 +02006104 rc = check_node_xpath(node);
Michal Vasko508a50d2016-09-07 14:50:33 +02006105 break;
Michal Vaskocf024702015-10-08 15:01:42 +02006106 default:
6107 LOGINT;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006108 break;
6109 }
6110
Radek Krejci54081ce2016-08-12 15:21:47 +02006111 if (has_str && !rc) {
6112 /* the string is no more needed in case of success.
6113 * In case of forward reference, we will try to resolve the string later */
Radek Krejci4f78b532016-02-17 13:43:00 +01006114 lydict_remove(mod->ctx, str_snode);
6115 }
6116
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006117 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006118}
6119
Michal Vaskof02e3742015-08-05 16:27:02 +02006120/* logs directly */
6121static void
Radek Krejci48464ed2016-03-17 15:44:09 +01006122print_unres_schema_item_fail(void *item, enum UNRES_ITEM type, void *str_node)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006123{
Michal Vaskocb34dc62016-05-20 14:38:37 +02006124 struct lyxml_elem *xml;
6125 struct lyxml_attr *attr;
Radek Krejcicbb473e2016-09-16 14:48:32 +02006126 struct unres_iffeat_data *iff_data;
Radek Krejci76e15e12016-06-22 11:02:24 +02006127 const char *type_name = NULL;
Michal Vaskocb34dc62016-05-20 14:38:37 +02006128
Michal Vaskof02e3742015-08-05 16:27:02 +02006129 switch (type) {
Michal Vaskof02e3742015-08-05 16:27:02 +02006130 case UNRES_IDENT:
Radek Krejci48464ed2016-03-17 15:44:09 +01006131 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "identity", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006132 break;
6133 case UNRES_TYPE_IDENTREF:
Radek Krejci48464ed2016-03-17 15:44:09 +01006134 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "identityref", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006135 break;
6136 case UNRES_TYPE_LEAFREF:
Radek Krejci48464ed2016-03-17 15:44:09 +01006137 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "leafref",
6138 ((struct lys_type *)item)->info.lref.path);
Michal Vaskof02e3742015-08-05 16:27:02 +02006139 break;
Radek Krejci3a5501d2016-07-18 22:03:34 +02006140 case UNRES_TYPE_DER_TPDF:
Michal Vaskof02e3742015-08-05 16:27:02 +02006141 case UNRES_TYPE_DER:
Michal Vaskocb34dc62016-05-20 14:38:37 +02006142 xml = (struct lyxml_elem *)((struct lys_type *)item)->der;
6143 if (xml->flags & LY_YANG_STRUCTURE_FLAG) {
6144 type_name = ((struct yang_type *)xml)->name;
6145 } else {
6146 LY_TREE_FOR(xml->attr, attr) {
6147 if ((attr->type == LYXML_ATTR_STD) && !strcmp(attr->name, "name")) {
6148 type_name = attr->value;
6149 break;
6150 }
6151 }
6152 assert(attr);
6153 }
6154 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "derived type", type_name);
Michal Vaskof02e3742015-08-05 16:27:02 +02006155 break;
Michal Vaskof02e3742015-08-05 16:27:02 +02006156 case UNRES_IFFEAT:
Radek Krejcicbb473e2016-09-16 14:48:32 +02006157 iff_data = str_node;
6158 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "if-feature", iff_data->fname);
Michal Vaskof02e3742015-08-05 16:27:02 +02006159 break;
Radek Krejcic79c6b12016-07-26 15:11:49 +02006160 case UNRES_FEATURE:
6161 LOGVRB("There are unresolved if-features for \"%s\" feature circular dependency check, it will be attempted later",
6162 ((struct lys_feature *)item)->name);
6163 break;
Michal Vaskof02e3742015-08-05 16:27:02 +02006164 case UNRES_USES:
Radek Krejci48464ed2016-03-17 15:44:09 +01006165 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "uses", ((struct lys_node_uses *)item)->name);
Michal Vaskof02e3742015-08-05 16:27:02 +02006166 break;
6167 case UNRES_TYPE_DFLT:
Radek Krejci2e2de832016-10-13 16:12:26 +02006168 if (str_node) {
6169 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "type default", (char *)str_node);
6170 } /* else no default value in the type itself, but we are checking some restrictions against
6171 * possible default value of some base type. The failure is caused by not resolved base type,
6172 * so it was already reported */
Michal Vaskof02e3742015-08-05 16:27:02 +02006173 break;
6174 case UNRES_CHOICE_DFLT:
Radek Krejci48464ed2016-03-17 15:44:09 +01006175 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "choice default", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006176 break;
6177 case UNRES_LIST_KEYS:
Radek Krejci48464ed2016-03-17 15:44:09 +01006178 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "list keys", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006179 break;
6180 case UNRES_LIST_UNIQ:
Radek Krejci48464ed2016-03-17 15:44:09 +01006181 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "list unique", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006182 break;
Michal Vasko7178e692016-02-12 15:58:05 +01006183 case UNRES_AUGMENT:
Radek Krejci48464ed2016-03-17 15:44:09 +01006184 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "augment target",
6185 ((struct lys_node_augment *)item)->target_name);
Michal Vasko7178e692016-02-12 15:58:05 +01006186 break;
Michal Vasko508a50d2016-09-07 14:50:33 +02006187 case UNRES_XPATH:
6188 LOGVRB("Resolving %s \"%s\" with the context node \"%s\" failed, it will be attempted later.", "XPath",
6189 (char *)str_node, ((struct lys_node *)item)->name);
6190 break;
Michal Vaskocf024702015-10-08 15:01:42 +02006191 default:
6192 LOGINT;
Michal Vaskof02e3742015-08-05 16:27:02 +02006193 break;
6194 }
6195}
6196
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006197/**
Michal Vaskobb211122015-08-19 14:03:11 +02006198 * @brief Resolve every unres schema item in the structure. Logs directly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006199 *
6200 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02006201 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006202 *
Michal Vasko92b8a382015-08-19 14:03:49 +02006203 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006204 */
Michal Vaskof02e3742015-08-05 16:27:02 +02006205int
Michal Vasko0bd29d12015-08-19 11:45:49 +02006206resolve_unres_schema(struct lys_module *mod, struct unres_schema *unres)
Michal Vaskof02e3742015-08-05 16:27:02 +02006207{
Radek Krejci010e54b2016-03-15 09:40:34 +01006208 uint32_t i, resolved = 0, unres_count, res_count;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006209 int rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006210
6211 assert(unres);
6212
Michal Vaskoe8734262016-09-29 14:12:06 +02006213 LOGVRB("Resolving \"%s\" unresolved schema nodes and their constraints...", mod->name);
Radek Krejci010e54b2016-03-15 09:40:34 +01006214 ly_vlog_hide(1);
Michal Vasko51054ca2015-08-12 12:20:00 +02006215
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006216 /* uses */
Michal Vasko51054ca2015-08-12 12:20:00 +02006217 do {
Michal Vasko88c29542015-11-27 14:57:53 +01006218 unres_count = 0;
6219 res_count = 0;
Michal Vasko51054ca2015-08-12 12:20:00 +02006220
6221 for (i = 0; i < unres->count; ++i) {
Radek Krejci018f1f52016-08-03 16:01:20 +02006222 /* UNRES_TYPE_LEAFREF must be resolved (for storing leafref target pointers);
Radek Krejcic79c6b12016-07-26 15:11:49 +02006223 * if-features are resolved here to make sure that we will have all if-features for
6224 * later check of feature circular dependency */
Radek Krejci018f1f52016-08-03 16:01:20 +02006225 if (unres->type[i] > UNRES_IDENT) {
Michal Vasko51054ca2015-08-12 12:20:00 +02006226 continue;
6227 }
Radek Krejci018f1f52016-08-03 16:01:20 +02006228 /* processes UNRES_USES, UNRES_IFFEAT, UNRES_TYPE_DER, UNRES_TYPE_DER_TPDF, UNRES_TYPE_LEAFREF,
Radek Krejcie00d2312016-08-12 15:27:49 +02006229 * UNRES_CHOICE_DFLT and UNRES_IDENT */
Michal Vasko51054ca2015-08-12 12:20:00 +02006230
Michal Vasko88c29542015-11-27 14:57:53 +01006231 ++unres_count;
Radek Krejci48464ed2016-03-17 15:44:09 +01006232 rc = resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006233 if (!rc) {
Michal Vasko51054ca2015-08-12 12:20:00 +02006234 unres->type[i] = UNRES_RESOLVED;
6235 ++resolved;
Michal Vasko88c29542015-11-27 14:57:53 +01006236 ++res_count;
Michal Vasko89e15322015-08-17 15:46:55 +02006237 } else if (rc == -1) {
Radek Krejci010e54b2016-03-15 09:40:34 +01006238 ly_vlog_hide(0);
Michal Vasko22af5ca2016-05-20 11:44:02 +02006239 /* print the error */
6240 resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006241 return -1;
Radek Krejcic2a180f2016-06-22 13:28:16 +02006242 } else {
6243 /* forward reference, erase ly_errno */
6244 ly_errno = LY_SUCCESS;
6245 ly_vecode = LYVE_SUCCESS;
Michal Vasko51054ca2015-08-12 12:20:00 +02006246 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006247 }
Michal Vasko88c29542015-11-27 14:57:53 +01006248 } while (res_count && (res_count < unres_count));
Michal Vasko51054ca2015-08-12 12:20:00 +02006249
Michal Vasko88c29542015-11-27 14:57:53 +01006250 if (res_count < unres_count) {
Michal Vasko22af5ca2016-05-20 11:44:02 +02006251 /* just print the errors */
6252 ly_vlog_hide(0);
6253
6254 for (i = 0; i < unres->count; ++i) {
Radek Krejci018f1f52016-08-03 16:01:20 +02006255 if (unres->type[i] > UNRES_IDENT) {
Michal Vasko22af5ca2016-05-20 11:44:02 +02006256 continue;
6257 }
6258 resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
6259 }
Michal Vasko92b8a382015-08-19 14:03:49 +02006260 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006261 }
6262
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006263 /* the rest */
6264 for (i = 0; i < unres->count; ++i) {
6265 if (unres->type[i] == UNRES_RESOLVED) {
6266 continue;
6267 }
Michal Vaskoc07187d2015-08-13 15:20:57 +02006268
Radek Krejci48464ed2016-03-17 15:44:09 +01006269 rc = resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
Radek Krejci010e54b2016-03-15 09:40:34 +01006270 if (rc == 0) {
Pavol Vican88e16c92016-09-07 15:41:50 +02006271 if (unres->type[i] == UNRES_LIST_UNIQ) {
6272 /* free the allocated structure */
6273 free(unres->item[i]);
6274 }
Radek Krejci010e54b2016-03-15 09:40:34 +01006275 unres->type[i] = UNRES_RESOLVED;
6276 ++resolved;
6277 } else if (rc == -1) {
6278 ly_vlog_hide(0);
Michal Vasko22af5ca2016-05-20 11:44:02 +02006279 /* print the error */
6280 resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
6281 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006282 }
6283 }
6284
Radek Krejci010e54b2016-03-15 09:40:34 +01006285 ly_vlog_hide(0);
6286
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006287 if (resolved < unres->count) {
Radek Krejci010e54b2016-03-15 09:40:34 +01006288 /* try to resolve the unresolved nodes again, it will not resolve anything, but it will print
6289 * all the validation errors
6290 */
6291 for (i = 0; i < unres->count; ++i) {
6292 if (unres->type[i] == UNRES_RESOLVED) {
6293 continue;
6294 }
Radek Krejci48464ed2016-03-17 15:44:09 +01006295 resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
Radek Krejci010e54b2016-03-15 09:40:34 +01006296 }
Michal Vasko92b8a382015-08-19 14:03:49 +02006297 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006298 }
6299
Michal Vaskoe8734262016-09-29 14:12:06 +02006300 LOGVRB("All \"%s\" schema nodes and constraints resolved.", mod->name);
Radek Krejcic071c542016-01-27 14:57:51 +01006301 unres->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006302 return EXIT_SUCCESS;
6303}
6304
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006305/**
Michal Vaskobb211122015-08-19 14:03:11 +02006306 * @brief Try to resolve an unres schema item with a string argument. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006307 *
6308 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02006309 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006310 * @param[in] item Item to resolve. Type determined by \p type.
6311 * @param[in] type Type of the unresolved item.
6312 * @param[in] str String argument.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006313 *
Michal Vasko3767fb22016-07-21 12:10:57 +02006314 * @return EXIT_SUCCESS on success, EXIT_FAILURE on storing the item in unres, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006315 */
6316int
Radek Krejci48464ed2016-03-17 15:44:09 +01006317unres_schema_add_str(struct lys_module *mod, struct unres_schema *unres, void *item, enum UNRES_ITEM type,
6318 const char *str)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006319{
Radek Krejci54081ce2016-08-12 15:21:47 +02006320 int rc;
6321 const char *dictstr;
6322
6323 dictstr = lydict_insert(mod->ctx, str, 0);
6324 rc = unres_schema_add_node(mod, unres, item, type, (struct lys_node *)dictstr);
6325
6326 if (rc == -1) {
6327 lydict_remove(mod->ctx, dictstr);
6328 }
6329 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006330}
6331
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006332/**
Michal Vaskobb211122015-08-19 14:03:11 +02006333 * @brief Try to resolve an unres schema item with a schema node argument. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006334 *
6335 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02006336 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006337 * @param[in] item Item to resolve. Type determined by \p type.
Michal Vasko88c29542015-11-27 14:57:53 +01006338 * @param[in] type Type of the unresolved item. UNRES_TYPE_DER is handled specially!
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006339 * @param[in] snode Schema node argument.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006340 *
Michal Vasko3767fb22016-07-21 12:10:57 +02006341 * @return EXIT_SUCCESS on success, EXIT_FIALURE on storing the item in unres, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006342 */
6343int
Michal Vasko0bd29d12015-08-19 11:45:49 +02006344unres_schema_add_node(struct lys_module *mod, struct unres_schema *unres, void *item, enum UNRES_ITEM type,
Radek Krejci48464ed2016-03-17 15:44:09 +01006345 struct lys_node *snode)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006346{
Michal Vaskoef486d72016-09-27 12:10:44 +02006347 int rc, log_hidden;
Michal Vasko88c29542015-11-27 14:57:53 +01006348 struct lyxml_elem *yin;
Radek Krejci010e54b2016-03-15 09:40:34 +01006349 char *path, *msg;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006350
Michal Vasko9bf425b2015-10-22 11:42:03 +02006351 assert(unres && item && ((type != UNRES_LEAFREF) && (type != UNRES_INSTID) && (type != UNRES_WHEN)
6352 && (type != UNRES_MUST)));
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006353
Michal Vaskoef486d72016-09-27 12:10:44 +02006354 if (*ly_vlog_hide_location()) {
6355 log_hidden = 1;
6356 } else {
6357 log_hidden = 0;
6358 ly_vlog_hide(1);
6359 }
Radek Krejci48464ed2016-03-17 15:44:09 +01006360 rc = resolve_unres_schema_item(mod, item, type, snode, unres);
Michal Vaskoef486d72016-09-27 12:10:44 +02006361 if (!log_hidden) {
6362 ly_vlog_hide(0);
6363 }
6364
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006365 if (rc != EXIT_FAILURE) {
Radek Krejci010e54b2016-03-15 09:40:34 +01006366 if (rc == -1 && ly_errno == LY_EVALID) {
Radek Krejci76e15e12016-06-22 11:02:24 +02006367 if (ly_log_level >= LY_LLERR) {
6368 path = strdup(ly_errpath());
6369 msg = strdup(ly_errmsg());
6370 LOGERR(LY_EVALID, "%s%s%s%s", msg, path[0] ? " (path: " : "", path[0] ? path : "", path[0] ? ")" : "");
6371 free(path);
6372 free(msg);
6373 }
Radek Krejci010e54b2016-03-15 09:40:34 +01006374 }
Radek Krejcid09d1a52016-08-11 14:05:45 +02006375 if (type == UNRES_LIST_UNIQ) {
6376 /* free the allocated structure */
6377 free(item);
Pavol Vican88e16c92016-09-07 15:41:50 +02006378 } else if (rc == -1 && type == UNRES_IFFEAT) {
6379 /* free the allocated resources */
6380 free(*((char **)item));
6381 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006382 return rc;
Radek Krejcif347abc2016-06-22 10:18:47 +02006383 } else {
6384 /* erase info about validation errors */
6385 ly_errno = LY_SUCCESS;
6386 ly_vecode = LYVE_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006387 }
6388
Radek Krejci48464ed2016-03-17 15:44:09 +01006389 print_unres_schema_item_fail(item, type, snode);
Michal Vaskof02e3742015-08-05 16:27:02 +02006390
Michal Vasko88c29542015-11-27 14:57:53 +01006391 /* HACK unlinking is performed here so that we do not do any (NS) copying in vain */
Radek Krejci3a5501d2016-07-18 22:03:34 +02006392 if (type == UNRES_TYPE_DER || type == UNRES_TYPE_DER_TPDF) {
Michal Vasko88c29542015-11-27 14:57:53 +01006393 yin = (struct lyxml_elem *)((struct lys_type *)item)->der;
Pavol Vicana0e4e672016-02-24 12:20:04 +01006394 if (!(yin->flags & LY_YANG_STRUCTURE_FLAG)) {
6395 lyxml_unlink_elem(mod->ctx, yin, 1);
6396 ((struct lys_type *)item)->der = (struct lys_tpdf *)yin;
6397 }
Michal Vasko88c29542015-11-27 14:57:53 +01006398 }
6399
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006400 unres->count++;
Michal Vasko253035f2015-12-17 16:58:13 +01006401 unres->item = ly_realloc(unres->item, unres->count*sizeof *unres->item);
6402 if (!unres->item) {
6403 LOGMEM;
6404 return -1;
6405 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006406 unres->item[unres->count-1] = item;
Michal Vasko253035f2015-12-17 16:58:13 +01006407 unres->type = ly_realloc(unres->type, unres->count*sizeof *unres->type);
6408 if (!unres->type) {
6409 LOGMEM;
6410 return -1;
6411 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006412 unres->type[unres->count-1] = type;
Michal Vasko253035f2015-12-17 16:58:13 +01006413 unres->str_snode = ly_realloc(unres->str_snode, unres->count*sizeof *unres->str_snode);
6414 if (!unres->str_snode) {
6415 LOGMEM;
6416 return -1;
6417 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006418 unres->str_snode[unres->count-1] = snode;
Radek Krejcic071c542016-01-27 14:57:51 +01006419 unres->module = ly_realloc(unres->module, unres->count*sizeof *unres->module);
6420 if (!unres->module) {
6421 LOGMEM;
6422 return -1;
6423 }
6424 unres->module[unres->count-1] = mod;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006425
Michal Vasko3767fb22016-07-21 12:10:57 +02006426 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006427}
6428
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006429/**
Michal Vaskobb211122015-08-19 14:03:11 +02006430 * @brief Duplicate an unres schema item. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006431 *
6432 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02006433 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006434 * @param[in] item Old item to be resolved.
6435 * @param[in] type Type of the old unresolved item.
6436 * @param[in] new_item New item to use in the duplicate.
6437 *
Radek Krejci9ff0a922016-07-14 13:08:05 +02006438 * @return EXIT_SUCCESS on success, EXIT_FAILURE if item is not in unres, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006439 */
Michal Vaskodad19402015-08-06 09:51:53 +02006440int
Michal Vasko0bd29d12015-08-19 11:45:49 +02006441unres_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 +02006442{
6443 int i;
Radek Krejcid09d1a52016-08-11 14:05:45 +02006444 struct unres_list_uniq aux_uniq;
Radek Krejcicbb473e2016-09-16 14:48:32 +02006445 struct unres_iffeat_data *iff_data;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006446
Michal Vaskocf024702015-10-08 15:01:42 +02006447 assert(item && new_item && ((type != UNRES_LEAFREF) && (type != UNRES_INSTID) && (type != UNRES_WHEN)));
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006448
Radek Krejcid09d1a52016-08-11 14:05:45 +02006449 /* hack for UNRES_LIST_UNIQ, which stores multiple items behind its item */
6450 if (type == UNRES_LIST_UNIQ) {
6451 aux_uniq.list = item;
6452 aux_uniq.expr = ((struct unres_list_uniq *)new_item)->expr;
6453 item = &aux_uniq;
6454 }
Michal Vasko878e38d2016-09-05 12:17:53 +02006455 i = unres_schema_find(unres, -1, item, type);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006456
6457 if (i == -1) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02006458 if (type == UNRES_LIST_UNIQ) {
6459 free(new_item);
6460 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02006461 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006462 }
6463
Radek Krejcic79c6b12016-07-26 15:11:49 +02006464 if ((type == UNRES_TYPE_LEAFREF) || (type == UNRES_USES) || (type == UNRES_TYPE_DFLT) ||
Radek Krejcib69f3232016-09-16 17:41:07 +02006465 (type == UNRES_FEATURE) || (type == UNRES_LIST_UNIQ)) {
Radek Krejci48464ed2016-03-17 15:44:09 +01006466 if (unres_schema_add_node(mod, unres, new_item, type, unres->str_snode[i]) == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006467 LOGINT;
6468 return -1;
6469 }
Radek Krejcicbb473e2016-09-16 14:48:32 +02006470 } else if (type == UNRES_IFFEAT) {
6471 /* duplicate unres_iffeature_data */
6472 iff_data = malloc(sizeof *iff_data);
6473 iff_data->fname = lydict_insert(mod->ctx, ((struct unres_iffeat_data *)unres->str_snode[i])->fname, 0);
6474 iff_data->node = ((struct unres_iffeat_data *)unres->str_snode[i])->node;
6475 if (unres_schema_add_node(mod, unres, new_item, type, (struct lys_node *)iff_data) == -1) {
6476 LOGINT;
6477 return -1;
6478 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006479 } else {
Radek Krejci48464ed2016-03-17 15:44:09 +01006480 if (unres_schema_add_str(mod, unres, new_item, type, unres->str_snode[i]) == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006481 LOGINT;
6482 return -1;
6483 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006484 }
Michal Vaskodad19402015-08-06 09:51:53 +02006485
6486 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006487}
6488
Michal Vaskof02e3742015-08-05 16:27:02 +02006489/* does not log */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006490int
Michal Vasko878e38d2016-09-05 12:17:53 +02006491unres_schema_find(struct unres_schema *unres, int start_on_backwards, void *item, enum UNRES_ITEM type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006492{
Michal Vasko878e38d2016-09-05 12:17:53 +02006493 int i;
Radek Krejcid09d1a52016-08-11 14:05:45 +02006494 struct unres_list_uniq *aux_uniq1, *aux_uniq2;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006495
Michal Vasko878e38d2016-09-05 12:17:53 +02006496 if (start_on_backwards > 0) {
6497 i = start_on_backwards;
6498 } else {
6499 i = unres->count - 1;
6500 }
6501 for (; i > -1; i--) {
6502 if (unres->type[i] != type) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02006503 continue;
6504 }
6505 if (type != UNRES_LIST_UNIQ) {
Michal Vasko878e38d2016-09-05 12:17:53 +02006506 if (unres->item[i] == item) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02006507 break;
6508 }
6509 } else {
6510 aux_uniq1 = (struct unres_list_uniq *)unres->item[i - 1];
6511 aux_uniq2 = (struct unres_list_uniq *)item;
6512 if ((aux_uniq1->list == aux_uniq2->list) && ly_strequal(aux_uniq1->expr, aux_uniq2->expr, 0)) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02006513 break;
6514 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006515 }
6516 }
6517
Michal Vasko878e38d2016-09-05 12:17:53 +02006518 return i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006519}
Michal Vasko8bcdf292015-08-19 14:04:43 +02006520
Michal Vaskoede9c472016-06-07 09:38:15 +02006521static void
6522unres_schema_free_item(struct ly_ctx *ctx, struct unres_schema *unres, uint32_t i)
6523{
6524 struct lyxml_elem *yin;
6525 struct yang_type *yang;
Radek Krejcicbb473e2016-09-16 14:48:32 +02006526 struct unres_iffeat_data *iff_data;
Michal Vaskoede9c472016-06-07 09:38:15 +02006527
6528 switch (unres->type[i]) {
Radek Krejci3a5501d2016-07-18 22:03:34 +02006529 case UNRES_TYPE_DER_TPDF:
Michal Vaskoede9c472016-06-07 09:38:15 +02006530 case UNRES_TYPE_DER:
6531 yin = (struct lyxml_elem *)((struct lys_type *)unres->item[i])->der;
6532 if (yin->flags & LY_YANG_STRUCTURE_FLAG) {
6533 yang =(struct yang_type *)yin;
6534 yang->type->base = yang->base;
6535 lydict_remove(ctx, yang->name);
6536 free(yang);
6537 } else {
6538 lyxml_free(ctx, yin);
6539 }
6540 break;
Pavol Vican88e16c92016-09-07 15:41:50 +02006541 case UNRES_IFFEAT:
Radek Krejcicbb473e2016-09-16 14:48:32 +02006542 iff_data = (struct unres_iffeat_data *)unres->str_snode[i];
6543 lydict_remove(ctx, iff_data->fname);
6544 free(unres->str_snode[i]);
Pavol Vican88e16c92016-09-07 15:41:50 +02006545 break;
Michal Vaskoede9c472016-06-07 09:38:15 +02006546 case UNRES_IDENT:
6547 case UNRES_TYPE_IDENTREF:
Michal Vaskoede9c472016-06-07 09:38:15 +02006548 case UNRES_TYPE_DFLT:
6549 case UNRES_CHOICE_DFLT:
6550 case UNRES_LIST_KEYS:
Michal Vaskoede9c472016-06-07 09:38:15 +02006551 lydict_remove(ctx, (const char *)unres->str_snode[i]);
6552 break;
Radek Krejcid09d1a52016-08-11 14:05:45 +02006553 case UNRES_LIST_UNIQ:
6554 free(unres->item[i]);
6555 break;
Michal Vaskoede9c472016-06-07 09:38:15 +02006556 default:
6557 break;
6558 }
6559 unres->type[i] = UNRES_RESOLVED;
6560}
6561
Michal Vasko88c29542015-11-27 14:57:53 +01006562void
Radek Krejcic071c542016-01-27 14:57:51 +01006563unres_schema_free(struct lys_module *module, struct unres_schema **unres)
Michal Vasko88c29542015-11-27 14:57:53 +01006564{
6565 uint32_t i;
Radek Krejcic071c542016-01-27 14:57:51 +01006566 unsigned int unresolved = 0;
Michal Vasko88c29542015-11-27 14:57:53 +01006567
Radek Krejcic071c542016-01-27 14:57:51 +01006568 if (!unres || !(*unres)) {
6569 return;
Michal Vasko88c29542015-11-27 14:57:53 +01006570 }
6571
Radek Krejcic071c542016-01-27 14:57:51 +01006572 assert(module || (*unres)->count == 0);
6573
6574 for (i = 0; i < (*unres)->count; ++i) {
6575 if ((*unres)->module[i] != module) {
6576 if ((*unres)->type[i] != UNRES_RESOLVED) {
6577 unresolved++;
6578 }
6579 continue;
6580 }
Michal Vaskoede9c472016-06-07 09:38:15 +02006581
6582 /* free heap memory for the specific item */
6583 unres_schema_free_item(module->ctx, *unres, i);
Radek Krejcic071c542016-01-27 14:57:51 +01006584 }
6585
Michal Vaskoede9c472016-06-07 09:38:15 +02006586 /* free it all */
Radek Krejcic071c542016-01-27 14:57:51 +01006587 if (!module || (!unresolved && !module->type)) {
6588 free((*unres)->item);
6589 free((*unres)->type);
6590 free((*unres)->str_snode);
6591 free((*unres)->module);
Radek Krejcic071c542016-01-27 14:57:51 +01006592 free((*unres));
6593 (*unres) = NULL;
6594 }
Michal Vasko88c29542015-11-27 14:57:53 +01006595}
6596
Radek Krejci9b6aad22016-09-20 15:55:51 +02006597static int resolve_union(struct lyd_node_leaf_list *leaf, struct lys_type *type);
6598
Radek Krejci7de36cf2016-09-12 16:18:50 +02006599static int
Radek Krejci9b6aad22016-09-20 15:55:51 +02006600resolve_leafref(struct lyd_node_leaf_list *leaf, struct lys_type *type)
Radek Krejci7de36cf2016-09-12 16:18:50 +02006601{
Radek Krejci7de36cf2016-09-12 16:18:50 +02006602 struct unres_data matches;
6603 uint32_t i;
6604
Radek Krejci9b6aad22016-09-20 15:55:51 +02006605 assert(type->base == LY_TYPE_LEAFREF);
6606
6607 /* init */
Radek Krejci7de36cf2016-09-12 16:18:50 +02006608 memset(&matches, 0, sizeof matches);
Radek Krejci7de36cf2016-09-12 16:18:50 +02006609
6610 /* EXIT_FAILURE return keeps leaf->value.lefref NULL, handled later */
Radek Krejci9b6aad22016-09-20 15:55:51 +02006611 if (resolve_path_arg_data((struct lyd_node *)leaf, type->info.lref.path, &matches) == -1) {
Radek Krejci7de36cf2016-09-12 16:18:50 +02006612 return -1;
6613 }
6614
6615 /* check that value matches */
6616 for (i = 0; i < matches.count; ++i) {
6617 if (ly_strequal(leaf->value_str, ((struct lyd_node_leaf_list *)matches.node[i])->value_str, 1)) {
6618 leaf->value.leafref = matches.node[i];
6619 break;
6620 }
6621 }
6622
6623 free(matches.node);
6624
6625 if (!leaf->value.leafref) {
6626 /* reference not found */
6627 if (type->info.lref.req > -1) {
6628 LOGVAL(LYE_NOLEAFREF, LY_VLOG_LYD, leaf, type->info.lref.path, leaf->value_str);
6629 return EXIT_FAILURE;
6630 } else {
6631 LOGVRB("There is no leafref with the value \"%s\", but it is not required.", leaf->value_str);
6632 }
6633 }
6634
6635 return EXIT_SUCCESS;
6636}
6637
Radek Krejci9b6aad22016-09-20 15:55:51 +02006638API LY_DATA_TYPE
6639lyd_leaf_type(const struct lyd_node_leaf_list *leaf)
6640{
6641 struct lyd_node *node;
6642 struct lys_type *type, *type_iter;
6643 lyd_val value;
6644 int f = 0, r;
6645
6646 if (!leaf || !(leaf->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
6647 return LY_TYPE_ERR;
6648 }
6649
6650 if (leaf->value_type > 0 && (leaf->value_type & LY_DATA_TYPE_MASK) != LY_TYPE_UNION &&
6651 (leaf->value_type & LY_DATA_TYPE_MASK) != LY_TYPE_LEAFREF) {
6652 /* we can get the type directly from the data node (it was already resolved) */
6653 return leaf->value_type & LY_DATA_TYPE_MASK;
6654 }
6655
6656 /* init */
6657 type = &((struct lys_node_leaf *)leaf->schema)->type;
6658 value = leaf->value;
6659 ly_vlog_hide(1);
6660
6661 /* resolve until we get the real data type */
6662 while (1) {
6663 /* get the correct data type from schema */
6664 switch (type->base) {
6665 case LY_TYPE_LEAFREF:
6666 type = &type->info.lref.target->type;
6667 break; /* continue in while loop */
6668 case LY_TYPE_UNION:
6669 type_iter = NULL;
6670 while ((type_iter = lyp_get_next_union_type(type, type_iter, &f))) {
6671 if (type_iter->base == LY_TYPE_LEAFREF) {
6672 if (type_iter->info.lref.req == -1) {
6673 /* target not required, so it always succeeds */
6674 break;
6675 } else {
6676 /* try to resolve leafref */
6677 memset(&((struct lyd_node_leaf_list *)leaf)->value, 0, sizeof leaf->value);
6678 r = resolve_leafref((struct lyd_node_leaf_list *)leaf, type_iter);
6679 /* revert leaf's content affected by resolve_leafref */
6680 ((struct lyd_node_leaf_list *)leaf)->value = value;
6681 if (!r) {
6682 /* success, we can continue with the leafref type */
6683 break;
6684 }
6685 }
6686 } else if (type_iter->base == LY_TYPE_INST) {
6687 if (type_iter->info.inst.req == -1) {
6688 /* target not required, so it always succeeds */
6689 return LY_TYPE_INST;
6690 } else {
6691 /* try to resolve instance-identifier */
6692 ly_errno = 0;
6693 node = resolve_instid((struct lyd_node *)leaf, leaf->value_str);
6694 if (!ly_errno && node) {
6695 /* the real type is instance-identifier */
6696 return LY_TYPE_INST;
6697 }
6698 }
6699 } else {
6700 r = lyp_parse_value_type((struct lyd_node_leaf_list *)leaf, type_iter, 1);
6701 /* revert leaf's content affected by resolve_leafref */
6702 ((struct lyd_node_leaf_list *)leaf)->value = value;
6703 if (!r) {
6704 /* we have the real type */
6705 return type_iter->base;
6706 }
6707 }
6708 f = 0;
6709 }
6710 /* erase ly_errno and ly_vecode */
6711 ly_errno = LY_SUCCESS;
6712 ly_vecode = LYVE_SUCCESS;
6713
6714 if (!type_iter) {
6715 LOGERR(LY_EINVAL, "Unable to get type from union \"%s\" with no valid type.", type->parent->name)
6716 return LY_TYPE_ERR;
6717 }
6718 type = type_iter;
6719 break;
6720 default:
6721 /* we have the real type */
6722 ly_vlog_hide(0);
6723 return type->base;
6724 }
6725 }
6726
6727 ly_vlog_hide(0);
6728 return LY_TYPE_ERR;
6729}
6730
6731static int
6732resolve_union(struct lyd_node_leaf_list *leaf, struct lys_type *type)
6733{
6734 struct lys_type *datatype = NULL;
6735 int f = 0;
6736
6737 assert(type->base == LY_TYPE_UNION);
6738
6739 memset(&leaf->value, 0, sizeof leaf->value);
6740 while ((datatype = lyp_get_next_union_type(type, datatype, &f))) {
6741 leaf->value_type = datatype->base;
6742
6743 if (datatype->base == LY_TYPE_LEAFREF) {
6744 /* try to resolve leafref */
6745 if (!resolve_leafref(leaf, datatype)) {
6746 /* success */
6747 break;
6748 }
6749 } else if (datatype->base == LY_TYPE_INST) {
6750 /* try to resolve instance-identifier */
6751 ly_errno = 0;
6752 leaf->value.instance = resolve_instid((struct lyd_node *)leaf, leaf->value_str);
6753 if (!ly_errno && (leaf->value.instance || datatype->info.inst.req == -1)) {
6754 /* success */
6755 break;
6756 }
6757 } else {
6758 if (!lyp_parse_value_type(leaf, datatype, 1)) {
6759 /* success */
6760 break;
6761 }
6762 }
6763 f = 0;
6764 }
6765 /* erase ly_errno and ly_vecode */
6766 ly_errno = LY_SUCCESS;
6767 ly_vecode = LYVE_SUCCESS;
6768
6769 if (!datatype) {
6770 /* failure */
6771 LOGVAL(LYE_INVAL, LY_VLOG_LYD, leaf, (leaf->value_str ? leaf->value_str : ""), leaf->schema->name);
6772 return EXIT_FAILURE;
6773 }
6774
6775 return EXIT_SUCCESS;
6776}
6777
Michal Vasko8bcdf292015-08-19 14:04:43 +02006778/**
6779 * @brief Resolve a single unres data item. Logs directly.
6780 *
Michal Vaskocf024702015-10-08 15:01:42 +02006781 * @param[in] node Data node to resolve.
Michal Vaskocf024702015-10-08 15:01:42 +02006782 * @param[in] type Type of the unresolved item.
Michal Vasko8bcdf292015-08-19 14:04:43 +02006783 *
6784 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
6785 */
Michal Vasko8ea2b7f2015-09-29 14:30:53 +02006786int
Radek Krejci48464ed2016-03-17 15:44:09 +01006787resolve_unres_data_item(struct lyd_node *node, enum UNRES_ITEM type)
Michal Vasko8bcdf292015-08-19 14:04:43 +02006788{
Michal Vasko0491ab32015-08-19 14:28:29 +02006789 int rc;
Michal Vasko83a6c462015-10-08 16:43:53 +02006790 struct lyd_node_leaf_list *leaf;
Michal Vasko8bcdf292015-08-19 14:04:43 +02006791 struct lys_node_leaf *sleaf;
Michal Vaskoc4280842016-04-19 16:10:42 +02006792 struct lyd_node *parent;
Michal Vasko8bcdf292015-08-19 14:04:43 +02006793
Michal Vasko83a6c462015-10-08 16:43:53 +02006794 leaf = (struct lyd_node_leaf_list *)node;
Michal Vaskocf024702015-10-08 15:01:42 +02006795 sleaf = (struct lys_node_leaf *)leaf->schema;
Michal Vasko8bcdf292015-08-19 14:04:43 +02006796
Michal Vaskocf024702015-10-08 15:01:42 +02006797 switch (type) {
6798 case UNRES_LEAFREF:
6799 assert(sleaf->type.base == LY_TYPE_LEAFREF);
Radek Krejci9b6aad22016-09-20 15:55:51 +02006800 return resolve_leafref(leaf, &sleaf->type);
Michal Vasko8bcdf292015-08-19 14:04:43 +02006801
Michal Vaskocf024702015-10-08 15:01:42 +02006802 case UNRES_INSTID:
Radek Krejci7de36cf2016-09-12 16:18:50 +02006803 assert(sleaf->type.base == LY_TYPE_INST);
Michal Vasko8bcdf292015-08-19 14:04:43 +02006804 ly_errno = 0;
Radek Krejci48464ed2016-03-17 15:44:09 +01006805 leaf->value.instance = resolve_instid(node, leaf->value_str);
Radek Krejci40f17b92016-02-03 14:30:43 +01006806 if (!leaf->value.instance) {
Michal Vasko8bcdf292015-08-19 14:04:43 +02006807 if (ly_errno) {
6808 return -1;
6809 } else if (sleaf->type.info.inst.req > -1) {
Michal Vasko6ac68282016-04-11 10:56:47 +02006810 LOGVAL(LYE_NOREQINS, LY_VLOG_LYD, leaf, leaf->value_str);
Michal Vasko8bcdf292015-08-19 14:04:43 +02006811 return EXIT_FAILURE;
6812 } else {
Michal Vasko9925e282016-09-02 12:45:14 +02006813 LOGVRB("There is no instance identifier \"%s\", but it is not required.", leaf->value_str);
Michal Vasko8bcdf292015-08-19 14:04:43 +02006814 }
6815 }
Michal Vaskocf024702015-10-08 15:01:42 +02006816 break;
6817
Radek Krejci7de36cf2016-09-12 16:18:50 +02006818 case UNRES_UNION:
6819 assert(sleaf->type.base == LY_TYPE_UNION);
Radek Krejci9b6aad22016-09-20 15:55:51 +02006820 return resolve_union(leaf, &sleaf->type);
Radek Krejci7de36cf2016-09-12 16:18:50 +02006821
Michal Vaskocf024702015-10-08 15:01:42 +02006822 case UNRES_WHEN:
Radek Krejci46165822016-08-26 14:06:27 +02006823 if ((rc = resolve_when(node, NULL))) {
Michal Vaskocf024702015-10-08 15:01:42 +02006824 return rc;
6825 }
6826 break;
6827
Michal Vaskobf19d252015-10-08 15:39:17 +02006828 case UNRES_MUST:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02006829 if ((rc = resolve_must(node, 0))) {
6830 return rc;
6831 }
6832 break;
6833
6834 case UNRES_MUST_INOUT:
6835 if ((rc = resolve_must(node, 1))) {
Michal Vaskobf19d252015-10-08 15:39:17 +02006836 return rc;
6837 }
6838 break;
6839
Michal Vaskoc4280842016-04-19 16:10:42 +02006840 case UNRES_EMPTYCONT:
6841 do {
6842 parent = node->parent;
6843 lyd_free(node);
6844 node = parent;
6845 } while (node && (node->schema->nodetype == LYS_CONTAINER) && !node->child
6846 && !((struct lys_node_container *)node->schema)->presence);
6847 break;
6848
Michal Vaskocf024702015-10-08 15:01:42 +02006849 default:
Michal Vasko8bcdf292015-08-19 14:04:43 +02006850 LOGINT;
6851 return -1;
6852 }
6853
6854 return EXIT_SUCCESS;
6855}
6856
6857/**
Radek Krejci0b7704f2016-03-18 12:16:14 +01006858 * @brief add data unres item
Michal Vasko8bcdf292015-08-19 14:04:43 +02006859 *
6860 * @param[in] unres Unres data structure to use.
Michal Vaskocf024702015-10-08 15:01:42 +02006861 * @param[in] node Data node to use.
Michal Vasko8bcdf292015-08-19 14:04:43 +02006862 *
Radek Krejci0b7704f2016-03-18 12:16:14 +01006863 * @return 0 on success, -1 on error.
Michal Vasko8bcdf292015-08-19 14:04:43 +02006864 */
6865int
Radek Krejci0b7704f2016-03-18 12:16:14 +01006866unres_data_add(struct unres_data *unres, struct lyd_node *node, enum UNRES_ITEM type)
Michal Vasko8bcdf292015-08-19 14:04:43 +02006867{
Radek Krejci03b71f72016-03-16 11:10:09 +01006868 assert(unres && node);
Michal Vaskoc4280842016-04-19 16:10:42 +02006869 assert((type == UNRES_LEAFREF) || (type == UNRES_INSTID) || (type == UNRES_WHEN) || (type == UNRES_MUST)
Michal Vaskoc8c810c2016-09-15 14:02:00 +02006870 || (type == UNRES_MUST_INOUT) || (type == UNRES_UNION) || (type == UNRES_EMPTYCONT));
Michal Vasko8bcdf292015-08-19 14:04:43 +02006871
Radek Krejci03b71f72016-03-16 11:10:09 +01006872 unres->count++;
Michal Vasko253035f2015-12-17 16:58:13 +01006873 unres->node = ly_realloc(unres->node, unres->count * sizeof *unres->node);
6874 if (!unres->node) {
6875 LOGMEM;
6876 return -1;
6877 }
Michal Vaskocf024702015-10-08 15:01:42 +02006878 unres->node[unres->count - 1] = node;
Michal Vasko253035f2015-12-17 16:58:13 +01006879 unres->type = ly_realloc(unres->type, unres->count * sizeof *unres->type);
6880 if (!unres->type) {
6881 LOGMEM;
6882 return -1;
6883 }
Michal Vaskocf024702015-10-08 15:01:42 +02006884 unres->type[unres->count - 1] = type;
Michal Vasko8bcdf292015-08-19 14:04:43 +02006885
Radek Krejci0b7704f2016-03-18 12:16:14 +01006886 if (type == UNRES_WHEN) {
6887 /* remove previous result */
6888 node->when_status = LYD_WHEN;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006889 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006890
6891 return EXIT_SUCCESS;
6892}
6893
6894/**
6895 * @brief Resolve every unres data item in the structure. Logs directly.
6896 *
Radek Krejci082c84f2016-10-17 16:33:06 +02006897 * If options includes LYD_OPT_TRUSTED, the data are considered trusted (when, must conditions are not expected,
6898 * unresolved leafrefs/instids are accepted).
6899 *
6900 * If options includes LYD_OPT_NOAUTODEL, the false resulting when condition on non-default nodes, the error is raised.
6901 *
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006902 * @param[in] unres Unres data structure to use.
Radek Krejci082c84f2016-10-17 16:33:06 +02006903 * @param[in,out] root Root node of the data tree, can be changed due to autodeletion.
6904 * @param[in] options Data options as described above.
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006905 *
6906 * @return EXIT_SUCCESS on success, -1 on error.
6907 */
6908int
Radek Krejci082c84f2016-10-17 16:33:06 +02006909resolve_unres_data(struct unres_data *unres, struct lyd_node **root, int options)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006910{
Radek Krejci0c0086a2016-03-24 15:20:28 +01006911 uint32_t i, j, first = 1, resolved = 0, del_items = 0, when_stmt = 0;
Radek Krejci010e54b2016-03-15 09:40:34 +01006912 int rc, progress;
Radek Krejci03b71f72016-03-16 11:10:09 +01006913 char *msg, *path;
Radek Krejci0b7704f2016-03-18 12:16:14 +01006914 struct lyd_node *parent;
Radek Krejci7de36cf2016-09-12 16:18:50 +02006915 struct lyd_node_leaf_list *leaf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006916
Radek Krejci082c84f2016-10-17 16:33:06 +02006917 assert(root);
Radek Krejci03b71f72016-03-16 11:10:09 +01006918 assert(unres);
Radek Krejci03b71f72016-03-16 11:10:09 +01006919
6920 if (!unres->count) {
6921 return EXIT_SUCCESS;
6922 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006923
Michal Vaskoa0ffcab2016-05-02 14:52:08 +02006924 LOGVRB("Resolving unresolved data nodes and their constraints...");
Radek Krejci010e54b2016-03-15 09:40:34 +01006925 ly_vlog_hide(1);
6926
Radek Krejci0b7704f2016-03-18 12:16:14 +01006927 /* when-stmt first */
Radek Krejci03b71f72016-03-16 11:10:09 +01006928 ly_errno = LY_SUCCESS;
6929 ly_vecode = LYVE_SUCCESS;
Radek Krejci010e54b2016-03-15 09:40:34 +01006930 do {
6931 progress = 0;
Michal Vasko6df94132016-09-22 11:08:09 +02006932 for (i = 0; i < unres->count; i++) {
Radek Krejci010e54b2016-03-15 09:40:34 +01006933 if (unres->type[i] != UNRES_WHEN) {
6934 continue;
6935 }
Radek Krejci082c84f2016-10-17 16:33:06 +02006936 assert(!(options & LYD_OPT_TRUSTED));
Radek Krejci0c0086a2016-03-24 15:20:28 +01006937 if (first) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01006938 /* count when-stmt nodes in unres list */
6939 when_stmt++;
6940 }
6941
6942 /* resolve when condition only when all parent when conditions are already resolved */
6943 for (parent = unres->node[i]->parent;
6944 parent && LYD_WHEN_DONE(parent->when_status);
6945 parent = parent->parent) {
6946 if (!parent->parent && (parent->when_status & LYD_WHEN_FALSE)) {
6947 /* the parent node was already unlinked, do not resolve this node,
6948 * it will be removed anyway, so just mark it as resolved
6949 */
6950 unres->node[i]->when_status |= LYD_WHEN_FALSE;
6951 unres->type[i] = UNRES_RESOLVED;
6952 resolved++;
6953 break;
6954 }
6955 }
6956 if (parent) {
6957 continue;
6958 }
Radek Krejci010e54b2016-03-15 09:40:34 +01006959
Radek Krejci48464ed2016-03-17 15:44:09 +01006960 rc = resolve_unres_data_item(unres->node[i], unres->type[i]);
Radek Krejci010e54b2016-03-15 09:40:34 +01006961 if (!rc) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01006962 if (unres->node[i]->when_status & LYD_WHEN_FALSE) {
Radek Krejci082c84f2016-10-17 16:33:06 +02006963 if ((options & LYD_OPT_NOAUTODEL) && !unres->node[i]->dflt) {
Radek Krejci03b71f72016-03-16 11:10:09 +01006964 /* false when condition */
6965 ly_vlog_hide(0);
Radek Krejci76e15e12016-06-22 11:02:24 +02006966 if (ly_log_level >= LY_LLERR) {
6967 path = strdup(ly_errpath());
6968 msg = strdup(ly_errmsg());
6969 LOGERR(LY_EVALID, "%s%s%s%s", msg,
6970 path[0] ? " (path: " : "", path[0] ? path : "", path[0] ? ")" : "");
6971 free(path);
6972 free(msg);
6973 }
Radek Krejci03b71f72016-03-16 11:10:09 +01006974 return -1;
Radek Krejci0b7704f2016-03-18 12:16:14 +01006975 } /* follows else */
6976
Radek Krejci0c0086a2016-03-24 15:20:28 +01006977 /* only unlink now, the subtree can contain another nodes stored in the unres list */
6978 /* if it has parent non-presence containers that would be empty, we should actually
6979 * remove the container
6980 */
Radek Krejci2537fd32016-09-07 16:22:41 +02006981 for (parent = unres->node[i];
6982 parent->parent && parent->parent->schema->nodetype == LYS_CONTAINER;
6983 parent = parent->parent) {
6984 if (((struct lys_node_container *)parent->parent->schema)->presence) {
6985 /* presence container */
6986 break;
Radek Krejci0c0086a2016-03-24 15:20:28 +01006987 }
Radek Krejci2537fd32016-09-07 16:22:41 +02006988 if (parent->next || parent->prev != parent) {
6989 /* non empty (the child we are in and we are going to remove is not the only child) */
6990 break;
6991 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01006992 }
Radek Krejci2537fd32016-09-07 16:22:41 +02006993 unres->node[i] = parent;
Radek Krejci0c0086a2016-03-24 15:20:28 +01006994
Radek Krejci0b7704f2016-03-18 12:16:14 +01006995 /* auto-delete */
6996 LOGVRB("auto-delete node \"%s\" due to when condition (%s)", ly_errpath(),
6997 ((struct lys_node_leaf *)unres->node[i]->schema)->when->cond);
Radek Krejci0c0086a2016-03-24 15:20:28 +01006998 if (*root && *root == unres->node[i]) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01006999 *root = (*root)->next;
Radek Krejci03b71f72016-03-16 11:10:09 +01007000 }
Radek Krejci0b7704f2016-03-18 12:16:14 +01007001
Radek Krejci0b7704f2016-03-18 12:16:14 +01007002 lyd_unlink(unres->node[i]);
7003 unres->type[i] = UNRES_DELETE;
7004 del_items++;
Radek Krejci51fd8162016-03-24 15:49:51 +01007005
7006 /* update the rest of unres items */
7007 for (j = 0; j < unres->count; j++) {
Radek Krejci3db819b2016-03-24 16:29:48 +01007008 if (unres->type[j] == UNRES_RESOLVED || unres->type[j] == UNRES_DELETE) {
Radek Krejci51fd8162016-03-24 15:49:51 +01007009 continue;
7010 }
7011
7012 /* test if the node is in subtree to be deleted */
7013 for (parent = unres->node[j]; parent; parent = parent->parent) {
7014 if (parent == unres->node[i]) {
7015 /* yes, it is */
7016 unres->type[j] = UNRES_RESOLVED;
7017 resolved++;
7018 break;
7019 }
7020 }
7021 }
Radek Krejci0b7704f2016-03-18 12:16:14 +01007022 } else {
7023 unres->type[i] = UNRES_RESOLVED;
Radek Krejci03b71f72016-03-16 11:10:09 +01007024 }
Radek Krejci0b7704f2016-03-18 12:16:14 +01007025 ly_errno = LY_SUCCESS;
7026 ly_vecode = LYVE_SUCCESS;
Radek Krejci010e54b2016-03-15 09:40:34 +01007027 resolved++;
7028 progress = 1;
7029 } else if (rc == -1) {
7030 ly_vlog_hide(0);
Michal Vasko76e73402016-08-24 16:00:13 +02007031 /* print only this last error */
7032 resolve_unres_data_item(unres->node[i], unres->type[i]);
Radek Krejci010e54b2016-03-15 09:40:34 +01007033 return -1;
Radek Krejcic2a180f2016-06-22 13:28:16 +02007034 } else {
7035 /* forward reference, erase ly_errno */
7036 ly_errno = LY_SUCCESS;
Radek Krejci010e54b2016-03-15 09:40:34 +01007037 }
7038 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01007039 first = 0;
Radek Krejci0b7704f2016-03-18 12:16:14 +01007040 } while (progress && resolved < when_stmt);
Radek Krejci010e54b2016-03-15 09:40:34 +01007041
Radek Krejci0b7704f2016-03-18 12:16:14 +01007042 /* do we have some unresolved when-stmt? */
Radek Krejcid940d732016-03-24 16:02:28 +01007043 if (when_stmt > resolved) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01007044 ly_vlog_hide(0);
Radek Krejci76e15e12016-06-22 11:02:24 +02007045 if (ly_log_level >= LY_LLERR) {
7046 path = strdup(ly_errpath());
7047 msg = strdup(ly_errmsg());
7048 LOGERR(LY_EVALID, "%s%s%s%s", msg, path[0] ? " (path: " : "", path[0] ? path : "", path[0] ? ")" : "");
7049 free(path);
7050 free(msg);
7051 }
Radek Krejci0b7704f2016-03-18 12:16:14 +01007052 return -1;
7053 }
7054
7055 for (i = 0; del_items && i < unres->count; i++) {
7056 /* we had some when-stmt resulted to false, so now we have to sanitize the unres list */
7057 if (unres->type[i] != UNRES_DELETE) {
7058 continue;
7059 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01007060 if (!unres->node[i]) {
7061 unres->type[i] = UNRES_RESOLVED;
7062 del_items--;
7063 continue;
Radek Krejci0b7704f2016-03-18 12:16:14 +01007064 }
7065
7066 /* really remove the complete subtree */
7067 lyd_free(unres->node[i]);
7068 unres->type[i] = UNRES_RESOLVED;
7069 del_items--;
7070 }
Radek Krejci010e54b2016-03-15 09:40:34 +01007071
7072 /* rest */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007073 for (i = 0; i < unres->count; ++i) {
Radek Krejci010e54b2016-03-15 09:40:34 +01007074 if (unres->type[i] == UNRES_RESOLVED) {
7075 continue;
7076 }
Radek Krejci082c84f2016-10-17 16:33:06 +02007077 assert(!(options & LYD_OPT_TRUSTED) || ((unres->type[i] != UNRES_MUST) && (unres->type[i] != UNRES_MUST_INOUT)));
Radek Krejci010e54b2016-03-15 09:40:34 +01007078
Radek Krejci48464ed2016-03-17 15:44:09 +01007079 rc = resolve_unres_data_item(unres->node[i], unres->type[i]);
Michal Vasko6df94132016-09-22 11:08:09 +02007080 if (rc == -1) {
Radek Krejci010e54b2016-03-15 09:40:34 +01007081 ly_vlog_hide(0);
Michal Vasko96b846c2016-05-18 13:28:58 +02007082 /* print only this last error */
7083 resolve_unres_data_item(unres->node[i], unres->type[i]);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007084 return -1;
Radek Krejci082c84f2016-10-17 16:33:06 +02007085 } 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 +02007086 unres->type[i] = UNRES_RESOLVED;
7087 resolved++;
Radek Krejci082c84f2016-10-17 16:33:06 +02007088 if (options & LYD_OPT_TRUSTED) {
Michal Vasko6df94132016-09-22 11:08:09 +02007089 /* accept it in this case */
7090 if (unres->type[i] == UNRES_LEAFREF) {
7091 LOGVRB("Leafref \"%s\" with value \"%s\" failed to be resolved.",
7092 ((struct lys_node_leaf *)unres->node[i]->schema)->type.info.lref.path,
7093 ((struct lyd_node_leaf_list *)unres->node[i])->value_str);
7094 } else {
7095 LOGVRB("Instance identifier \"%s\" failed to be resolved.",
7096 ((struct lyd_node_leaf_list *)unres->node[i])->value_str);
7097 }
7098 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007099 }
7100 }
7101
Radek Krejci010e54b2016-03-15 09:40:34 +01007102 ly_vlog_hide(0);
7103 if (resolved < unres->count) {
7104 /* try to resolve the unresolved data again, it will not resolve anything, but it will print
7105 * all the validation errors
7106 */
7107 for (i = 0; i < unres->count; ++i) {
Radek Krejci7de36cf2016-09-12 16:18:50 +02007108 if (unres->type[i] == UNRES_UNION) {
7109 /* does not make sense to print specific errors for all
7110 * the data types, just print that the value is invalid */
7111 leaf = (struct lyd_node_leaf_list *)unres->node[i];
7112 LOGVAL(LYE_INVAL, LY_VLOG_LYD, unres->node[i], (leaf->value_str ? leaf->value_str : ""),
7113 leaf->schema->name);
7114 } else if (unres->type[i] != UNRES_RESOLVED) {
7115 resolve_unres_data_item(unres->node[i], unres->type[i]);
Radek Krejci010e54b2016-03-15 09:40:34 +01007116 }
Radek Krejci010e54b2016-03-15 09:40:34 +01007117 }
7118 return -1;
7119 }
7120
Michal Vaskoa0ffcab2016-05-02 14:52:08 +02007121 LOGVRB("All data nodes and constraints resolved.");
Radek Krejci010e54b2016-03-15 09:40:34 +01007122 unres->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007123 return EXIT_SUCCESS;
7124}