blob: 76dc3b18486a9e02dfe937191f2853546cd72783 [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 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
16 * distribution.
17 * 3. Neither the name of the Company nor the names of its contributors
18 * may be used to endorse or promote products derived from this
19 * software without specific prior written permission.
20 */
21
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +020022#define _GNU_SOURCE
23
24#include <stdlib.h>
25#include <assert.h>
26#include <string.h>
27#include <ctype.h>
Michal Vaskoe7fc19c2015-08-05 16:24:39 +020028#include <limits.h>
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +020029
30#include "libyang.h"
31#include "resolve.h"
32#include "common.h"
Michal Vaskocf024702015-10-08 15:01:42 +020033#include "xpath.h"
Michal Vasko1dca6882015-10-22 14:29:42 +020034#include "parser.h"
Michal Vasko88c29542015-11-27 14:57:53 +010035#include "xml_internal.h"
Radek Krejci41912fe2015-10-22 10:22:12 +020036#include "dict_private.h"
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +020037#include "tree_internal.h"
38
Michal Vasko730dfdf2015-08-11 14:48:05 +020039/**
Radek Krejci6dc53a22015-08-17 13:27:59 +020040 * @brief Parse an identifier.
41 *
42 * ;; An identifier MUST NOT start with (('X'|'x') ('M'|'m') ('L'|'l'))
43 * identifier = (ALPHA / "_")
44 * *(ALPHA / DIGIT / "_" / "-" / ".")
45 *
Michal Vaskobb211122015-08-19 14:03:11 +020046 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +020047 *
48 * @return Number of characters successfully parsed.
49 */
Michal Vasko249e6b52015-08-19 11:08:52 +020050int
Radek Krejci6dc53a22015-08-17 13:27:59 +020051parse_identifier(const char *id)
52{
53 int parsed = 0;
54
55 if (((id[0] == 'x') || (id[0] == 'X'))
56 && ((id[1] == 'm') || (id[0] == 'M'))
57 && ((id[2] == 'l') || (id[2] == 'L'))) {
58 return -parsed;
59 }
60
61 if (!isalpha(id[0]) && (id[0] != '_')) {
62 return -parsed;
63 }
64
65 ++parsed;
66 ++id;
67
68 while (isalnum(id[0]) || (id[0] == '_') || (id[0] == '-') || (id[0] == '.')) {
69 ++parsed;
70 ++id;
71 }
72
73 return parsed;
74}
75
76/**
77 * @brief Parse a node-identifier.
78 *
Michal Vasko723e50c2015-10-20 15:20:29 +020079 * node-identifier = [module-name ":"] identifier
Radek Krejci6dc53a22015-08-17 13:27:59 +020080 *
Michal Vaskobb211122015-08-19 14:03:11 +020081 * @param[in] id Identifier to use.
Michal Vasko723e50c2015-10-20 15:20:29 +020082 * @param[out] mod_name Points to the module name, NULL if there is not any.
83 * @param[out] mod_name_len Length of the module name, 0 if there is not any.
Radek Krejci6dc53a22015-08-17 13:27:59 +020084 * @param[out] name Points to the node name.
85 * @param[out] nam_len Length of the node name.
86 *
87 * @return Number of characters successfully parsed,
88 * positive on success, negative on failure.
89 */
90static int
Michal Vasko723e50c2015-10-20 15:20:29 +020091parse_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 +020092{
93 int parsed = 0, ret;
94
95 assert(id);
Michal Vasko723e50c2015-10-20 15:20:29 +020096 if (mod_name) {
97 *mod_name = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +020098 }
Michal Vasko723e50c2015-10-20 15:20:29 +020099 if (mod_name_len) {
100 *mod_name_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200101 }
102 if (name) {
103 *name = NULL;
104 }
105 if (nam_len) {
106 *nam_len = 0;
107 }
108
109 if ((ret = parse_identifier(id)) < 1) {
110 return ret;
111 }
112
Michal Vasko723e50c2015-10-20 15:20:29 +0200113 if (mod_name) {
114 *mod_name = id;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200115 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200116 if (mod_name_len) {
117 *mod_name_len = ret;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200118 }
119
120 parsed += ret;
121 id += ret;
122
123 /* there is prefix */
124 if (id[0] == ':') {
125 ++parsed;
126 ++id;
127
128 /* there isn't */
129 } else {
Michal Vasko723e50c2015-10-20 15:20:29 +0200130 if (name && mod_name) {
131 *name = *mod_name;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200132 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200133 if (mod_name) {
134 *mod_name = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200135 }
136
Michal Vasko723e50c2015-10-20 15:20:29 +0200137 if (nam_len && mod_name_len) {
138 *nam_len = *mod_name_len;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200139 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200140 if (mod_name_len) {
141 *mod_name_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200142 }
143
144 return parsed;
145 }
146
147 /* identifier (node name) */
148 if ((ret = parse_identifier(id)) < 1) {
149 return -parsed+ret;
150 }
151
152 if (name) {
153 *name = id;
154 }
155 if (nam_len) {
156 *nam_len = ret;
157 }
158
159 return parsed+ret;
160}
161
162/**
163 * @brief Parse a path-predicate (leafref).
164 *
165 * path-predicate = "[" *WSP path-equality-expr *WSP "]"
166 * path-equality-expr = node-identifier *WSP "=" *WSP path-key-expr
167 *
Michal Vaskobb211122015-08-19 14:03:11 +0200168 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200169 * @param[out] prefix Points to the prefix, NULL if there is not any.
170 * @param[out] pref_len Length of the prefix, 0 if there is not any.
171 * @param[out] name Points to the node name.
172 * @param[out] nam_len Length of the node name.
173 * @param[out] path_key_expr Points to the path-key-expr.
174 * @param[out] pke_len Length of the path-key-expr.
175 * @param[out] has_predicate Flag to mark whether there is another predicate following.
176 *
177 * @return Number of characters successfully parsed,
178 * positive on success, negative on failure.
179 */
180static int
Michal Vasko23b61ec2015-08-19 11:19:50 +0200181parse_path_predicate(const char *id, const char **prefix, int *pref_len, const char **name, int *nam_len,
182 const char **path_key_expr, int *pke_len, int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200183{
184 const char *ptr;
185 int parsed = 0, ret;
186
187 assert(id);
188 if (prefix) {
189 *prefix = NULL;
190 }
191 if (pref_len) {
192 *pref_len = 0;
193 }
194 if (name) {
195 *name = NULL;
196 }
197 if (nam_len) {
198 *nam_len = 0;
199 }
200 if (path_key_expr) {
201 *path_key_expr = NULL;
202 }
203 if (pke_len) {
204 *pke_len = 0;
205 }
206 if (has_predicate) {
207 *has_predicate = 0;
208 }
209
210 if (id[0] != '[') {
211 return -parsed;
212 }
213
214 ++parsed;
215 ++id;
216
217 while (isspace(id[0])) {
218 ++parsed;
219 ++id;
220 }
221
222 if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len)) < 1) {
223 return -parsed+ret;
224 }
225
226 parsed += ret;
227 id += ret;
228
229 while (isspace(id[0])) {
230 ++parsed;
231 ++id;
232 }
233
234 if (id[0] != '=') {
235 return -parsed;
236 }
237
238 ++parsed;
239 ++id;
240
241 while (isspace(id[0])) {
242 ++parsed;
243 ++id;
244 }
245
246 if ((ptr = strchr(id, ']')) == NULL) {
247 return -parsed;
248 }
249
250 --ptr;
251 while (isspace(ptr[0])) {
252 --ptr;
253 }
254 ++ptr;
255
256 ret = ptr-id;
257 if (path_key_expr) {
258 *path_key_expr = id;
259 }
260 if (pke_len) {
261 *pke_len = ret;
262 }
263
264 parsed += ret;
265 id += ret;
266
267 while (isspace(id[0])) {
268 ++parsed;
269 ++id;
270 }
271
272 assert(id[0] == ']');
273
274 if (id[1] == '[') {
275 *has_predicate = 1;
276 }
277
278 return parsed+1;
279}
280
281/**
282 * @brief Parse a path-key-expr (leafref). First call parses "current()", all
283 * the ".." and the first node-identifier, other calls parse a single
284 * node-identifier each.
285 *
286 * path-key-expr = current-function-invocation *WSP "/" *WSP
287 * rel-path-keyexpr
288 * rel-path-keyexpr = 1*(".." *WSP "/" *WSP)
289 * *(node-identifier *WSP "/" *WSP)
290 * node-identifier
291 *
Michal Vaskobb211122015-08-19 14:03:11 +0200292 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200293 * @param[out] prefix Points to the prefix, NULL if there is not any.
294 * @param[out] pref_len Length of the prefix, 0 if there is not any.
295 * @param[out] name Points to the node name.
296 * @param[out] nam_len Length of the node name.
297 * @param[out] parent_times Number of ".." in the path. Must be 0 on the first call,
298 * must not be changed between consecutive calls.
299 * @return Number of characters successfully parsed,
300 * positive on success, negative on failure.
301 */
302static int
Michal Vasko23b61ec2015-08-19 11:19:50 +0200303parse_path_key_expr(const char *id, const char **prefix, int *pref_len, const char **name, int *nam_len,
304 int *parent_times)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200305{
306 int parsed = 0, ret, par_times = 0;
307
308 assert(id);
309 assert(parent_times);
310 if (prefix) {
311 *prefix = NULL;
312 }
313 if (pref_len) {
314 *pref_len = 0;
315 }
316 if (name) {
317 *name = NULL;
318 }
319 if (nam_len) {
320 *nam_len = 0;
321 }
322
323 if (!*parent_times) {
324 /* current-function-invocation *WSP "/" *WSP rel-path-keyexpr */
325 if (strncmp(id, "current()", 9)) {
326 return -parsed;
327 }
328
329 parsed += 9;
330 id += 9;
331
332 while (isspace(id[0])) {
333 ++parsed;
334 ++id;
335 }
336
337 if (id[0] != '/') {
338 return -parsed;
339 }
340
341 ++parsed;
342 ++id;
343
344 while (isspace(id[0])) {
345 ++parsed;
346 ++id;
347 }
348
349 /* rel-path-keyexpr */
350 if (strncmp(id, "..", 2)) {
351 return -parsed;
352 }
353 ++par_times;
354
355 parsed += 2;
356 id += 2;
357
358 while (isspace(id[0])) {
359 ++parsed;
360 ++id;
361 }
362 }
363
364 /* 1*(".." *WSP "/" *WSP) *(node-identifier *WSP "/" *WSP) node-identifier
365 *
366 * first parent reference with whitespaces already parsed
367 */
368 if (id[0] != '/') {
369 return -parsed;
370 }
371
372 ++parsed;
373 ++id;
374
375 while (isspace(id[0])) {
376 ++parsed;
377 ++id;
378 }
379
380 while (!strncmp(id, "..", 2) && !*parent_times) {
381 ++par_times;
382
383 parsed += 2;
384 id += 2;
385
386 while (isspace(id[0])) {
387 ++parsed;
388 ++id;
389 }
390
391 if (id[0] != '/') {
392 return -parsed;
393 }
394
395 ++parsed;
396 ++id;
397
398 while (isspace(id[0])) {
399 ++parsed;
400 ++id;
401 }
402 }
403
404 if (!*parent_times) {
405 *parent_times = par_times;
406 }
407
408 /* all parent references must be parsed at this point */
409 if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len)) < 1) {
410 return -parsed+ret;
411 }
412
413 parsed += ret;
414 id += ret;
415
416 return parsed;
417}
418
419/**
420 * @brief Parse path-arg (leafref).
421 *
422 * path-arg = absolute-path / relative-path
423 * absolute-path = 1*("/" (node-identifier *path-predicate))
424 * relative-path = 1*(".." "/") descendant-path
425 *
Michal Vaskobb211122015-08-19 14:03:11 +0200426 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200427 * @param[out] prefix Points to the prefix, NULL if there is not any.
428 * @param[out] pref_len Length of the prefix, 0 if there is not any.
429 * @param[out] name Points to the node name.
430 * @param[out] nam_len Length of the node name.
431 * @param[out] parent_times Number of ".." in the path. Must be 0 on the first call,
432 * must not be changed between consecutive calls. -1 if the
433 * path is relative.
434 * @param[out] has_predicate Flag to mark whether there is a predicate specified.
435 *
436 * @return Number of characters successfully parsed,
437 * positive on success, negative on failure.
438 */
439static int
Michal Vasko23b61ec2015-08-19 11:19:50 +0200440parse_path_arg(const char *id, const char **prefix, int *pref_len, const char **name, int *nam_len, int *parent_times,
441 int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200442{
443 int parsed = 0, ret, par_times = 0;
444
445 assert(id);
446 assert(parent_times);
447 if (prefix) {
448 *prefix = NULL;
449 }
450 if (pref_len) {
451 *pref_len = 0;
452 }
453 if (name) {
454 *name = NULL;
455 }
456 if (nam_len) {
457 *nam_len = 0;
458 }
459 if (has_predicate) {
460 *has_predicate = 0;
461 }
462
463 if (!*parent_times && !strncmp(id, "..", 2)) {
464 ++par_times;
465
466 parsed += 2;
467 id += 2;
468
469 while (!strncmp(id, "/..", 3)) {
470 ++par_times;
471
472 parsed += 3;
473 id += 3;
474 }
475 }
476
477 if (!*parent_times) {
478 if (par_times) {
479 *parent_times = par_times;
480 } else {
481 *parent_times = -1;
482 }
483 }
484
485 if (id[0] != '/') {
486 return -parsed;
487 }
488
489 /* skip '/' */
490 ++parsed;
491 ++id;
492
493 /* node-identifier ([prefix:]identifier) */
494 if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len)) < 1) {
495 return -parsed-ret;
496 }
497
498 parsed += ret;
499 id += ret;
500
501 /* there is no predicate */
502 if ((id[0] == '/') || !id[0]) {
503 return parsed;
504 } else if (id[0] != '[') {
505 return -parsed;
506 }
507
508 if (has_predicate) {
509 *has_predicate = 1;
510 }
511
512 return parsed;
513}
514
515/**
Michal Vaskof39142b2015-10-21 11:40:05 +0200516 * @brief Parse instance-identifier in JSON data format. That means that prefixes
Michal Vasko1f2cc332015-08-19 11:18:32 +0200517 * (which are mandatory) are actually model names.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200518 *
519 * instance-identifier = 1*("/" (node-identifier *predicate))
520 *
Michal Vaskobb211122015-08-19 14:03:11 +0200521 * @param[in] id Identifier to use.
Michal Vasko1f2cc332015-08-19 11:18:32 +0200522 * @param[out] model Points to the model name.
523 * @param[out] mod_len Length of the model name.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200524 * @param[out] name Points to the node name.
525 * @param[out] nam_len Length of the node name.
526 * @param[out] has_predicate Flag to mark whether there is a predicate specified.
527 *
528 * @return Number of characters successfully parsed,
529 * positive on success, negative on failure.
530 */
531static int
Michal Vaskof39142b2015-10-21 11:40:05 +0200532parse_instance_identifier(const char *id, const char **model, int *mod_len, const char **name, int *nam_len,
533 int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200534{
535 int parsed = 0, ret;
536
537 assert(id);
Michal Vasko1f2cc332015-08-19 11:18:32 +0200538 if (model) {
539 *model = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200540 }
Michal Vasko1f2cc332015-08-19 11:18:32 +0200541 if (mod_len) {
542 *mod_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200543 }
544 if (name) {
545 *name = NULL;
546 }
547 if (nam_len) {
548 *nam_len = 0;
549 }
550 if (has_predicate) {
551 *has_predicate = 0;
552 }
553
554 if (id[0] != '/') {
555 return -parsed;
556 }
557
558 ++parsed;
559 ++id;
560
Michal Vasko1f2cc332015-08-19 11:18:32 +0200561 if ((ret = parse_node_identifier(id, model, mod_len, name, nam_len)) < 1) {
Radek Krejci6dc53a22015-08-17 13:27:59 +0200562 return -parsed+ret;
Michal Vasko1f2cc332015-08-19 11:18:32 +0200563 } else if (model && !*model) {
564 return -parsed;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200565 }
566
567 parsed += ret;
568 id += ret;
569
570 if ((id[0] == '[') && has_predicate) {
571 *has_predicate = 1;
572 }
573
574 return parsed;
575}
576
577/**
Michal Vaskof39142b2015-10-21 11:40:05 +0200578 * @brief Parse predicate (instance-identifier) in JSON data format. That means that prefixes
Michal Vasko1f2cc332015-08-19 11:18:32 +0200579 * (which are mandatory) are actually model names.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200580 *
581 * predicate = "[" *WSP (predicate-expr / pos) *WSP "]"
582 * predicate-expr = (node-identifier / ".") *WSP "=" *WSP
583 * ((DQUOTE string DQUOTE) /
584 * (SQUOTE string SQUOTE))
585 * pos = non-negative-integer-value
586 *
Michal Vaskobb211122015-08-19 14:03:11 +0200587 * @param[in] id Identifier to use.
Michal Vasko1f2cc332015-08-19 11:18:32 +0200588 * @param[out] model Points to the model name.
589 * @param[out] mod_len Length of the model name.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200590 * @param[out] name Points to the node name. Can be identifier (from node-identifier), "." or pos.
591 * @param[out] nam_len Length of the node name.
592 * @param[out] value Value the node-identifier must have (string from the grammar),
593 * NULL if there is not any.
594 * @param[out] val_len Length of the value, 0 if there is not any.
595 * @param[out] has_predicate Flag to mark whether there is a predicate specified.
596 *
597 * @return Number of characters successfully parsed,
598 * positive on success, negative on failure.
599 */
600static int
Michal Vaskof39142b2015-10-21 11:40:05 +0200601parse_predicate(const char *id, const char **model, int *mod_len, const char **name, int *nam_len,
602 const char **value, int *val_len, int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200603{
604 const char *ptr;
605 int parsed = 0, ret;
606 char quote;
607
608 assert(id);
Michal Vasko1f2cc332015-08-19 11:18:32 +0200609 if (model) {
610 *model = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200611 }
Michal Vasko1f2cc332015-08-19 11:18:32 +0200612 if (mod_len) {
613 *mod_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200614 }
615 if (name) {
616 *name = NULL;
617 }
618 if (nam_len) {
619 *nam_len = 0;
620 }
621 if (value) {
622 *value = NULL;
623 }
624 if (val_len) {
625 *val_len = 0;
626 }
627 if (has_predicate) {
628 *has_predicate = 0;
629 }
630
631 if (id[0] != '[') {
632 return -parsed;
633 }
634
635 ++parsed;
636 ++id;
637
638 while (isspace(id[0])) {
639 ++parsed;
640 ++id;
641 }
642
643 /* pos */
644 if (isdigit(id[0])) {
645 if (name) {
646 *name = id;
647 }
648
649 if (id[0] == '0') {
650 ++parsed;
651 ++id;
652
653 if (isdigit(id[0])) {
654 return -parsed;
655 }
656 }
657
658 while (isdigit(id[0])) {
659 ++parsed;
660 ++id;
661 }
662
663 if (nam_len) {
664 *nam_len = id-(*name);
665 }
666
667 /* "." */
668 } else if (id[0] == '.') {
669 if (name) {
670 *name = id;
671 }
672 if (nam_len) {
673 *nam_len = 1;
674 }
675
676 ++parsed;
677 ++id;
678
679 /* node-identifier */
680 } else {
Michal Vasko1f2cc332015-08-19 11:18:32 +0200681 if ((ret = parse_node_identifier(id, model, mod_len, name, nam_len)) < 1) {
Radek Krejci6dc53a22015-08-17 13:27:59 +0200682 return -parsed+ret;
Michal Vasko1f2cc332015-08-19 11:18:32 +0200683 } else if (model && !*model) {
684 return -parsed;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200685 }
Michal Vasko1f2cc332015-08-19 11:18:32 +0200686
687 parsed += ret;
688 id += ret;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200689 }
690
691 while (isspace(id[0])) {
692 ++parsed;
693 ++id;
694 }
695
696 if (id[0] != '=') {
697 return -parsed;
698 }
699
700 ++parsed;
701 ++id;
702
703 while (isspace(id[0])) {
704 ++parsed;
705 ++id;
706 }
707
708 /* ((DQUOTE string DQUOTE) / (SQUOTE string SQUOTE)) */
709 if ((id[0] == '\"') || (id[0] == '\'')) {
710 quote = id[0];
711
712 ++parsed;
713 ++id;
714
715 if ((ptr = strchr(id, quote)) == NULL) {
716 return -parsed;
717 }
718 ret = ptr-id;
719
720 if (value) {
721 *value = id;
722 }
723 if (val_len) {
724 *val_len = ret;
725 }
726
727 parsed += ret+1;
728 id += ret+1;
729 } else {
730 return -parsed;
731 }
732
733 while (isspace(id[0])) {
734 ++parsed;
735 ++id;
736 }
737
738 if (id[0] != ']') {
739 return -parsed;
740 }
741
742 ++parsed;
743 ++id;
744
745 if ((id[0] == '[') && has_predicate) {
746 *has_predicate = 1;
747 }
748
749 return parsed;
750}
751
752/**
753 * @brief Parse schema-nodeid.
754 *
755 * schema-nodeid = absolute-schema-nodeid /
756 * descendant-schema-nodeid
757 * absolute-schema-nodeid = 1*("/" node-identifier)
758 * descendant-schema-nodeid =
759 * node-identifier
760 * absolute-schema-nodeid
761 *
Michal Vaskobb211122015-08-19 14:03:11 +0200762 * @param[in] id Identifier to use.
Michal Vasko723e50c2015-10-20 15:20:29 +0200763 * @param[out] mod_name Points to the module name, NULL if there is not any.
764 * @param[out] mod_name_len Length of the module name, 0 if there is not any.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200765 * @param[out] name Points to the node name. Can be identifier (from node-identifier), "." or pos.
766 * @param[out] nam_len Length of the node name.
767 * @param[out] is_relative Flag to mark whether the nodeid is absolute or descendant. Must be -1
768 * on the first call, must not be changed between consecutive calls.
769 *
770 * @return Number of characters successfully parsed,
771 * positive on success, negative on failure.
772 */
773static int
Michal Vasko723e50c2015-10-20 15:20:29 +0200774parse_schema_nodeid(const char *id, const char **mod_name, int *mod_name_len, const char **name, int *nam_len,
Michal Vasko23b61ec2015-08-19 11:19:50 +0200775 int *is_relative)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200776{
777 int parsed = 0, ret;
778
779 assert(id);
780 assert(is_relative);
Michal Vasko723e50c2015-10-20 15:20:29 +0200781 if (mod_name) {
782 *mod_name = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200783 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200784 if (mod_name_len) {
785 *mod_name_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200786 }
787 if (name) {
788 *name = NULL;
789 }
790 if (nam_len) {
791 *nam_len = 0;
792 }
793
794 if (id[0] != '/') {
795 if (*is_relative != -1) {
796 return -parsed;
797 } else {
798 *is_relative = 1;
799 }
800 } else {
801 if (*is_relative == -1) {
802 *is_relative = 0;
803 }
804 ++parsed;
805 ++id;
806 }
807
Michal Vasko723e50c2015-10-20 15:20:29 +0200808 if ((ret = parse_node_identifier(id, mod_name, mod_name_len, name, nam_len)) < 1) {
Radek Krejci6dc53a22015-08-17 13:27:59 +0200809 return -parsed+ret;
810 }
811
812 return parsed+ret;
813}
814
815/**
Michal Vasko3edeaf72016-02-11 13:17:43 +0100816 * @brief Resolve (find) a data node based on a schema-nodeid.
817 *
818 * Used for resolving unique statements - so id is expected to be relative and local (without reference to a different
819 * module).
820 *
821 */
822struct lyd_node *
823resolve_data_descendant_schema_nodeid(const char *nodeid, struct lyd_node *start)
824{
825 char *str, *token, *p;
826 struct lyd_node *result = start, *iter;
827 const struct lys_node *schema = NULL;
828
829 assert(nodeid && start);
830
831 if (nodeid[0] == '/') {
832 return NULL;
833 }
834
835 str = p = strdup(nodeid);
836 if (!str) {
837 LOGMEM;
838 return NULL;
839 }
840 while (p) {
841 token = p;
842 p = strchr(p, '/');
843 if (p) {
844 *p = '\0';
845 p++;
846 }
847
848 schema = NULL;
849 if (resolve_descendant_schema_nodeid(token, result->schema, LYS_LEAF, &schema) || !schema) {
850 free(str);
851 return NULL;
852 }
853
854 LY_TREE_FOR(result, iter) {
855 if (iter->schema == schema) {
856 break;
857 }
858 }
859
860 if (!p) {
861 /* final result */
862 result = iter;
863 } else {
864 result = iter->child;
865 }
866 }
867 free(str);
868
869 return result;
870}
871
872/* start - relative, module - absolute, -1 error, EXIT_SUCCESS ok (but ret can still be NULL), >0 unexpected char on ret - 1 */
873int
874resolve_augment_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_module *module,
875 const struct lys_node **ret)
876{
877 const char *name, *mod_name, *id;
878 const struct lys_node *sibling;
879 int r, nam_len, mod_name_len, is_relative = -1;
880 /* resolved import module from the start module, it must match the next node-name-match sibling */
Michal Vasko6c629ac2016-02-15 14:08:23 +0100881 const struct lys_module *prefix_mod, *start_mod;
Michal Vasko3edeaf72016-02-11 13:17:43 +0100882
883 assert(nodeid && (start || module) && !(start && module) && ret);
884
885 id = nodeid;
886
887 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative)) < 1) {
888 return ((id - nodeid) - r) + 1;
889 }
890 id += r;
891
892 if ((is_relative && !start) || (!is_relative && !module)) {
893 return -1;
894 }
895
896 /* descendant-schema-nodeid */
897 if (is_relative) {
898 start_mod = start->module;
899
900 /* absolute-schema-nodeid */
901 } else {
902 start_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
Michal Vaskoe2905632016-02-11 15:42:24 +0100903 if (!start_mod) {
904 return -1;
905 }
Michal Vasko3edeaf72016-02-11 13:17:43 +0100906 start = start_mod->data;
907 }
908
909 while (1) {
910 sibling = NULL;
911 while ((sibling = lys_getnext(sibling, lys_parent(start), start_mod,
912 LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT))) {
913 /* name match */
914 if ((sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len])
915 || (!strncmp(name, "input", 5) && (nam_len == 5) && (sibling->nodetype == LYS_INPUT))
916 || (!strncmp(name, "output", 6) && (nam_len == 6) && (sibling->nodetype == LYS_OUTPUT))) {
917
918 /* module check */
919 prefix_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
920 if (!prefix_mod) {
921 return -1;
922 }
Michal Vasko6c629ac2016-02-15 14:08:23 +0100923 if (prefix_mod != lys_node_module(sibling)) {
Michal Vasko3edeaf72016-02-11 13:17:43 +0100924 continue;
925 }
926
927 /* the result node? */
928 if (!id[0]) {
929 *ret = sibling;
930 return EXIT_SUCCESS;
931 }
932
933 /* check for shorthand cases - then 'start' does not change */
934 if (!sibling->parent || (sibling->parent->nodetype != LYS_CHOICE)
935 || (sibling->nodetype == LYS_CASE)) {
936 start = sibling->child;
937 }
938 break;
939 }
940 }
941
942 /* no match */
943 if (!sibling) {
944 return EXIT_SUCCESS;
945 }
946
947 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative)) < 1) {
948 return ((id - nodeid) - r) + 1;
949 }
950 id += r;
951 }
952
953 /* cannot get here */
954 LOGINT;
955 return -1;
956}
957
958/* unique, refine, -1 error, EXIT_SUCCESS ok (but ret can still be NULL), >0 unexpected char on ret - 1 */
959int
960resolve_descendant_schema_nodeid(const char *nodeid, const struct lys_node *start, int ret_nodetype,
961 const struct lys_node **ret)
962{
963 const char *name, *mod_name, *id;
964 const struct lys_node *sibling;
965 int r, nam_len, mod_name_len, is_relative = -1;
966 /* resolved import module from the start module, it must match the next node-name-match sibling */
Michal Vasko6c629ac2016-02-15 14:08:23 +0100967 const struct lys_module *prefix_mod, *module;
Michal Vasko3edeaf72016-02-11 13:17:43 +0100968
969 assert(nodeid && start && ret);
970 assert(!(ret_nodetype & (LYS_USES | LYS_AUGMENT)) && ((ret_nodetype == LYS_GROUPING) || !(ret_nodetype & LYS_GROUPING)));
971
972 id = nodeid;
973 module = start->module;
974
975 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative)) < 1) {
976 return ((id - nodeid) - r) + 1;
977 }
978 id += r;
979
980 if (!is_relative) {
981 return -1;
982 }
983
984 while (1) {
985 sibling = NULL;
986 while ((sibling = lys_getnext(sibling, lys_parent(start), module,
987 LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE))) {
988 /* name match */
989 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
990
991 /* module check */
992 prefix_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
993 if (!prefix_mod) {
994 return -1;
995 }
Michal Vasko6c629ac2016-02-15 14:08:23 +0100996 if (prefix_mod != lys_node_module(sibling)) {
Michal Vasko3edeaf72016-02-11 13:17:43 +0100997 continue;
998 }
999
1000 /* the result node? */
1001 if (!id[0]) {
1002 if (!(sibling->nodetype & ret_nodetype)) {
1003 /* wrong node type, too bad */
1004 continue;
1005 }
1006 *ret = sibling;
1007 return EXIT_SUCCESS;
1008 }
1009
1010 /* check for shorthand cases - then 'start' does not change */
1011 if (!sibling->parent || (sibling->parent->nodetype != LYS_CHOICE)
1012 || (sibling->nodetype == LYS_CASE)) {
1013 start = sibling->child;
1014 }
1015 break;
1016 }
1017 }
1018
1019 /* no match */
1020 if (!sibling) {
1021 return EXIT_SUCCESS;
1022 }
1023
1024 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative)) < 1) {
1025 return ((id - nodeid) - r) + 1;
1026 }
1027 id += r;
1028 }
1029
1030 /* cannot get here */
1031 LOGINT;
1032 return -1;
1033}
1034
1035/* choice default */
1036int
1037resolve_choice_default_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_node **ret)
1038{
1039 /* cannot actually be a path */
1040 if (strchr(nodeid, '/')) {
1041 return -1;
1042 }
1043
1044 return resolve_descendant_schema_nodeid(nodeid, start, LYS_NO_RPC_NOTIF_NODE, ret);
1045}
1046
1047/* uses, -1 error, EXIT_SUCCESS ok (but ret can still be NULL), >0 unexpected char on ret - 1 */
1048static int
1049resolve_uses_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_node_grp **ret)
1050{
1051 const struct lys_module *module;
1052 const char *mod_prefix, *name;
1053 int i, mod_prefix_len, nam_len;
1054
1055 /* parse the identifier, it must be parsed on one call */
1056 if (((i = parse_node_identifier(nodeid, &mod_prefix, &mod_prefix_len, &name, &nam_len)) < 1) || nodeid[i]) {
1057 return -i + 1;
1058 }
1059
1060 module = lys_get_import_module(start->module, mod_prefix, mod_prefix_len, NULL, 0);
1061 if (!module) {
1062 return -1;
1063 }
1064 if (module != start->module) {
1065 start = module->data;
1066 }
1067
1068 *ret = lys_find_grouping_up(name, (struct lys_node *)start);
1069
1070 return EXIT_SUCCESS;
1071}
1072
1073int
1074resolve_absolute_schema_nodeid(const char *nodeid, const struct lys_module *module, int ret_nodetype,
1075 const struct lys_node **ret)
1076{
1077 const char *name, *mod_name, *id;
1078 const struct lys_node *sibling, *start;
1079 int r, nam_len, mod_name_len, is_relative = -1;
Michal Vasko6c629ac2016-02-15 14:08:23 +01001080 const struct lys_module *prefix_mod, *abs_start_mod;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001081
1082 assert(nodeid && module && ret);
1083 assert(!(ret_nodetype & (LYS_USES | LYS_AUGMENT)) && ((ret_nodetype == LYS_GROUPING) || !(ret_nodetype & LYS_GROUPING)));
1084
1085 id = nodeid;
1086 start = module->data;
1087
1088 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative)) < 1) {
1089 return ((id - nodeid) - r) + 1;
1090 }
1091 id += r;
1092
1093 if (is_relative) {
1094 return -1;
1095 }
1096
1097 abs_start_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
Michal Vaskoe2905632016-02-11 15:42:24 +01001098 if (!abs_start_mod) {
1099 return -1;
1100 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001101
1102 while (1) {
1103 sibling = NULL;
1104 while ((sibling = lys_getnext(sibling, lys_parent(start), abs_start_mod, LYS_GETNEXT_WITHCHOICE
1105 | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT | LYS_GETNEXT_WITHGROUPING))) {
1106 /* name match */
1107 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
1108
1109 /* module check */
1110 prefix_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
1111 if (!prefix_mod) {
1112 return -1;
1113 }
Michal Vasko6c629ac2016-02-15 14:08:23 +01001114 if (prefix_mod != lys_node_module(sibling)) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001115 continue;
1116 }
1117
1118 /* the result node? */
1119 if (!id[0]) {
1120 if (!(sibling->nodetype & ret_nodetype)) {
1121 /* wrong node type, too bad */
1122 continue;
1123 }
1124 *ret = sibling;
1125 return EXIT_SUCCESS;
1126 }
1127
1128 /* check for shorthand cases - then 'start' does not change */
1129 if (!sibling->parent || (sibling->parent->nodetype != LYS_CHOICE)
1130 || (sibling->nodetype == LYS_CASE)) {
1131 start = sibling->child;
1132 }
1133 break;
1134 }
1135 }
1136
1137 /* no match */
1138 if (!sibling) {
1139 return EXIT_SUCCESS;
1140 }
1141
1142 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative)) < 1) {
1143 return ((id - nodeid) - r) + 1;
1144 }
1145 id += r;
1146 }
1147
1148 /* cannot get here */
1149 LOGINT;
1150 return -1;
1151}
1152
1153/* cannot return LYS_GROUPING, LYS_AUGMENT, LYS_USES */
1154int
1155resolve_json_absolute_schema_nodeid(const char *nodeid, struct ly_ctx *ctx, const struct lys_node **ret)
1156{
1157 char *str;
1158 const char *name, *mod_name, *id;
1159 const struct lys_node *sibling, *start;
1160 int r, nam_len, mod_name_len, is_relative = -1;
1161 /* resolved import module from the start module, it must match the next node-name-match sibling */
Michal Vasko6c629ac2016-02-15 14:08:23 +01001162 const struct lys_module *prefix_mod, *module, *prev_mod = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001163
1164 assert(nodeid && ctx && ret);
1165
1166 id = nodeid;
1167
1168 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative)) < 1) {
1169 return ((id - nodeid) - r) + 1;
1170 }
1171 id += r;
1172
1173 if (is_relative) {
1174 return -1;
1175 }
1176
Michal Vasko00980152016-02-17 13:10:33 +01001177 str = strndup(mod_name, mod_name_len);
Michal Vasko3edeaf72016-02-11 13:17:43 +01001178 module = ly_ctx_get_module(ctx, str, NULL);
1179 free(str);
1180 if (!module) {
1181 return -1;
1182 }
1183 start = module->data;
1184
1185 while (1) {
1186 sibling = NULL;
1187 while ((sibling = lys_getnext(sibling, lys_parent(start), module,
1188 LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT))) {
1189 /* name match */
1190 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
1191
1192 /* module check */
1193 if (mod_name) {
1194 prefix_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
1195 if (!prefix_mod) {
1196 return -1;
1197 }
1198 } else {
1199 prefix_mod = prev_mod;
1200 }
Michal Vasko6c629ac2016-02-15 14:08:23 +01001201 if (prefix_mod != lys_node_module(sibling)) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001202 continue;
1203 }
1204
1205 /* the result node? */
1206 if (!id[0]) {
1207 *ret = sibling;
1208 return EXIT_SUCCESS;
1209 }
1210
1211 /* check for shorthand cases - then 'start' does not change */
1212 if (!sibling->parent || (sibling->parent->nodetype != LYS_CHOICE)
1213 || (sibling->nodetype == LYS_CASE)) {
1214 start = sibling->child;
1215 }
1216
1217 /* update prev mod */
1218 prev_mod = start->module;
1219 break;
1220 }
1221 }
1222
1223 /* no match */
1224 if (!sibling) {
1225 return EXIT_SUCCESS;
1226 }
1227
1228 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative)) < 1) {
1229 return ((id - nodeid) - r) + 1;
1230 }
1231 id += r;
1232 }
1233
1234 /* cannot get here */
1235 LOGINT;
1236 return -1;
1237}
1238
1239/**
Michal Vasko730dfdf2015-08-11 14:48:05 +02001240 * @brief Resolves length or range intervals. Does not log.
1241 * Syntax is assumed to be correct, *local_intv MUST be NULL.
1242 *
1243 * @param[in] str_restr The restriction as a string.
1244 * @param[in] type The type of the restriction.
1245 * @param[in] superior_restr Flag whether to check superior
1246 * types.
1247 * @param[out] local_intv The final interval structure.
1248 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001249 * @return EXIT_SUCCESS on succes, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001250 */
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001251int
Michal Vasko23b61ec2015-08-19 11:19:50 +02001252resolve_len_ran_interval(const char *str_restr, struct lys_type *type, int superior_restr,
1253 struct len_ran_intv** local_intv)
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001254{
1255 /* 0 - unsigned, 1 - signed, 2 - floating point */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001256 int kind, rc = EXIT_SUCCESS;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001257 int64_t local_smin, local_smax;
1258 uint64_t local_umin, local_umax;
1259 long double local_fmin, local_fmax;
1260 const char *seg_ptr, *ptr;
Michal Vaskoe01eca52015-08-13 14:42:02 +02001261 struct len_ran_intv *tmp_local_intv = NULL, *tmp_intv, *intv = NULL;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001262
1263 switch (type->base) {
1264 case LY_TYPE_BINARY:
1265 kind = 0;
1266 local_umin = 0;
1267 local_umax = 18446744073709551615UL;
1268
1269 if (!str_restr && type->info.binary.length) {
1270 str_restr = type->info.binary.length->expr;
1271 }
1272 break;
1273 case LY_TYPE_DEC64:
1274 kind = 2;
1275 local_fmin = -9223372036854775808.0;
1276 local_fmin /= 1 << type->info.dec64.dig;
1277 local_fmax = 9223372036854775807.0;
1278 local_fmax /= 1 << type->info.dec64.dig;
1279
1280 if (!str_restr && type->info.dec64.range) {
1281 str_restr = type->info.dec64.range->expr;
1282 }
1283 break;
1284 case LY_TYPE_INT8:
1285 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01001286 local_smin = __INT64_C(-128);
1287 local_smax = __INT64_C(127);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001288
1289 if (!str_restr && type->info.num.range) {
1290 str_restr = type->info.num.range->expr;
1291 }
1292 break;
1293 case LY_TYPE_INT16:
1294 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01001295 local_smin = __INT64_C(-32768);
1296 local_smax = __INT64_C(32767);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001297
1298 if (!str_restr && type->info.num.range) {
1299 str_restr = type->info.num.range->expr;
1300 }
1301 break;
1302 case LY_TYPE_INT32:
1303 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01001304 local_smin = __INT64_C(-2147483648);
1305 local_smax = __INT64_C(2147483647);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001306
1307 if (!str_restr && type->info.num.range) {
1308 str_restr = type->info.num.range->expr;
1309 }
1310 break;
1311 case LY_TYPE_INT64:
1312 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01001313 local_smin = __INT64_C(-9223372036854775807) - __INT64_C(1);
1314 local_smax = __INT64_C(9223372036854775807);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001315
1316 if (!str_restr && type->info.num.range) {
1317 str_restr = type->info.num.range->expr;
1318 }
1319 break;
1320 case LY_TYPE_UINT8:
1321 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01001322 local_umin = __UINT64_C(0);
1323 local_umax = __UINT64_C(255);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001324
1325 if (!str_restr && type->info.num.range) {
1326 str_restr = type->info.num.range->expr;
1327 }
1328 break;
1329 case LY_TYPE_UINT16:
1330 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01001331 local_umin = __UINT64_C(0);
1332 local_umax = __UINT64_C(65535);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001333
1334 if (!str_restr && type->info.num.range) {
1335 str_restr = type->info.num.range->expr;
1336 }
1337 break;
1338 case LY_TYPE_UINT32:
1339 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01001340 local_umin = __UINT64_C(0);
1341 local_umax = __UINT64_C(4294967295);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001342
1343 if (!str_restr && type->info.num.range) {
1344 str_restr = type->info.num.range->expr;
1345 }
1346 break;
1347 case LY_TYPE_UINT64:
1348 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01001349 local_umin = __UINT64_C(0);
1350 local_umax = __UINT64_C(18446744073709551615);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001351
1352 if (!str_restr && type->info.num.range) {
1353 str_restr = type->info.num.range->expr;
1354 }
1355 break;
1356 case LY_TYPE_STRING:
1357 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01001358 local_umin = __UINT64_C(0);
1359 local_umax = __UINT64_C(18446744073709551615);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001360
1361 if (!str_restr && type->info.str.length) {
1362 str_restr = type->info.str.length->expr;
1363 }
1364 break;
1365 default:
1366 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001367 return -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001368 }
1369
1370 /* process superior types */
1371 if (type->der && superior_restr) {
Michal Vasko0c888fd2015-08-11 15:54:08 +02001372 if (resolve_len_ran_interval(NULL, &type->der->type, superior_restr, &intv)) {
1373 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001374 return -1;
Michal Vasko0c888fd2015-08-11 15:54:08 +02001375 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001376 assert(!intv || (intv->kind == kind));
1377 }
1378
1379 if (!str_restr) {
1380 /* we are validating data and not have any restriction, but a superior type might have */
1381 if (type->der && !superior_restr && !intv) {
Michal Vasko0c888fd2015-08-11 15:54:08 +02001382 if (resolve_len_ran_interval(NULL, &type->der->type, superior_restr, &intv)) {
1383 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001384 return -1;
Michal Vasko0c888fd2015-08-11 15:54:08 +02001385 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001386 assert(!intv || (intv->kind == kind));
1387 }
1388 *local_intv = intv;
1389 return EXIT_SUCCESS;
1390 }
1391
1392 /* adjust local min and max */
1393 if (intv) {
1394 tmp_intv = intv;
1395
1396 if (kind == 0) {
1397 local_umin = tmp_intv->value.uval.min;
1398 } else if (kind == 1) {
1399 local_smin = tmp_intv->value.sval.min;
1400 } else if (kind == 2) {
1401 local_fmin = tmp_intv->value.fval.min;
1402 }
1403
1404 while (tmp_intv->next) {
1405 tmp_intv = tmp_intv->next;
1406 }
1407
1408 if (kind == 0) {
1409 local_umax = tmp_intv->value.uval.max;
1410 } else if (kind == 1) {
1411 local_smax = tmp_intv->value.sval.max;
1412 } else if (kind == 2) {
1413 local_fmax = tmp_intv->value.fval.max;
1414 }
1415 }
1416
1417 /* finally parse our restriction */
1418 seg_ptr = str_restr;
1419 while (1) {
Michal Vaskoe01eca52015-08-13 14:42:02 +02001420 if (!*local_intv && !tmp_local_intv) {
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001421 *local_intv = malloc(sizeof **local_intv);
1422 tmp_local_intv = *local_intv;
1423 } else {
1424 tmp_local_intv->next = malloc(sizeof **local_intv);
1425 tmp_local_intv = tmp_local_intv->next;
1426 }
Michal Vasko253035f2015-12-17 16:58:13 +01001427 if (!tmp_local_intv) {
1428 LOGMEM;
1429 return -1;
1430 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001431
1432 tmp_local_intv->kind = kind;
1433 tmp_local_intv->next = NULL;
1434
1435 /* min */
1436 ptr = seg_ptr;
1437 while (isspace(ptr[0])) {
1438 ++ptr;
1439 }
1440 if (isdigit(ptr[0]) || (ptr[0] == '+') || (ptr[0] == '-')) {
1441 if (kind == 0) {
1442 tmp_local_intv->value.uval.min = atoll(ptr);
1443 } else if (kind == 1) {
1444 tmp_local_intv->value.sval.min = atoll(ptr);
1445 } else if (kind == 2) {
1446 tmp_local_intv->value.fval.min = atoll(ptr);
1447 }
1448
1449 if ((ptr[0] == '+') || (ptr[0] == '-')) {
1450 ++ptr;
1451 }
1452 while (isdigit(ptr[0])) {
1453 ++ptr;
1454 }
1455 } else if (!strncmp(ptr, "min", 3)) {
1456 if (kind == 0) {
1457 tmp_local_intv->value.uval.min = local_umin;
1458 } else if (kind == 1) {
1459 tmp_local_intv->value.sval.min = local_smin;
1460 } else if (kind == 2) {
1461 tmp_local_intv->value.fval.min = local_fmin;
1462 }
1463
1464 ptr += 3;
1465 } else if (!strncmp(ptr, "max", 3)) {
1466 if (kind == 0) {
1467 tmp_local_intv->value.uval.min = local_umax;
1468 } else if (kind == 1) {
1469 tmp_local_intv->value.sval.min = local_smax;
1470 } else if (kind == 2) {
1471 tmp_local_intv->value.fval.min = local_fmax;
1472 }
1473
1474 ptr += 3;
1475 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02001476 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001477 rc = -1;
Michal Vasko0c888fd2015-08-11 15:54:08 +02001478 goto cleanup;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001479 }
1480
1481 while (isspace(ptr[0])) {
1482 ptr++;
1483 }
1484
1485 /* no interval or interval */
1486 if ((ptr[0] == '|') || !ptr[0]) {
1487 if (kind == 0) {
1488 tmp_local_intv->value.uval.max = tmp_local_intv->value.uval.min;
1489 } else if (kind == 1) {
1490 tmp_local_intv->value.sval.max = tmp_local_intv->value.sval.min;
1491 } else if (kind == 2) {
1492 tmp_local_intv->value.fval.max = tmp_local_intv->value.fval.min;
1493 }
1494 } else if (!strncmp(ptr, "..", 2)) {
1495 /* skip ".." */
1496 ptr += 2;
1497 while (isspace(ptr[0])) {
1498 ++ptr;
1499 }
1500
1501 /* max */
1502 if (isdigit(ptr[0]) || (ptr[0] == '+') || (ptr[0] == '-')) {
1503 if (kind == 0) {
1504 tmp_local_intv->value.uval.max = atoll(ptr);
1505 } else if (kind == 1) {
1506 tmp_local_intv->value.sval.max = atoll(ptr);
1507 } else if (kind == 2) {
1508 tmp_local_intv->value.fval.max = atoll(ptr);
1509 }
1510 } else if (!strncmp(ptr, "max", 3)) {
1511 if (kind == 0) {
1512 tmp_local_intv->value.uval.max = local_umax;
1513 } else if (kind == 1) {
1514 tmp_local_intv->value.sval.max = local_smax;
1515 } else if (kind == 2) {
1516 tmp_local_intv->value.fval.max = local_fmax;
1517 }
1518 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02001519 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001520 rc = -1;
Michal Vasko0c888fd2015-08-11 15:54:08 +02001521 goto cleanup;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001522 }
1523 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02001524 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001525 rc = -1;
Michal Vasko0c888fd2015-08-11 15:54:08 +02001526 goto cleanup;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001527 }
1528
1529 /* next segment (next OR) */
1530 seg_ptr = strchr(seg_ptr, '|');
1531 if (!seg_ptr) {
1532 break;
1533 }
1534 seg_ptr++;
1535 }
1536
1537 /* check local restrictions against superior ones */
1538 if (intv) {
1539 tmp_intv = intv;
1540 tmp_local_intv = *local_intv;
1541
1542 while (tmp_local_intv && tmp_intv) {
1543 /* reuse local variables */
1544 if (kind == 0) {
1545 local_umin = tmp_local_intv->value.uval.min;
1546 local_umax = tmp_local_intv->value.uval.max;
1547
1548 /* it must be in this interval */
1549 if ((local_umin >= tmp_intv->value.uval.min) && (local_umin <= tmp_intv->value.uval.max)) {
1550 /* this interval is covered, next one */
1551 if (local_umax <= tmp_intv->value.uval.max) {
1552 tmp_local_intv = tmp_local_intv->next;
1553 continue;
1554 /* ascending order of restrictions -> fail */
1555 } else {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001556 rc = -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001557 goto cleanup;
1558 }
1559 }
1560 } else if (kind == 1) {
1561 local_smin = tmp_local_intv->value.sval.min;
1562 local_smax = tmp_local_intv->value.sval.max;
1563
1564 if ((local_smin >= tmp_intv->value.sval.min) && (local_smin <= tmp_intv->value.sval.max)) {
1565 if (local_smax <= tmp_intv->value.sval.max) {
1566 tmp_local_intv = tmp_local_intv->next;
1567 continue;
1568 } else {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001569 rc = -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001570 goto cleanup;
1571 }
1572 }
1573 } else if (kind == 2) {
1574 local_fmin = tmp_local_intv->value.fval.min;
1575 local_fmax = tmp_local_intv->value.fval.max;
1576
1577 if ((local_fmin >= tmp_intv->value.fval.min) && (local_fmin <= tmp_intv->value.fval.max)) {
1578 if (local_fmax <= tmp_intv->value.fval.max) {
1579 tmp_local_intv = tmp_local_intv->next;
1580 continue;
1581 } else {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001582 rc = -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001583 goto cleanup;
1584 }
1585 }
1586 }
1587
1588 tmp_intv = tmp_intv->next;
1589 }
1590
1591 /* some interval left uncovered -> fail */
1592 if (tmp_local_intv) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001593 rc = -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001594 }
1595
1596 }
1597
1598cleanup:
1599 while (intv) {
1600 tmp_intv = intv->next;
1601 free(intv);
1602 intv = tmp_intv;
1603 }
1604
1605 /* fail */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001606 if (rc) {
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001607 while (*local_intv) {
1608 tmp_local_intv = (*local_intv)->next;
1609 free(*local_intv);
1610 *local_intv = tmp_local_intv;
1611 }
1612 }
1613
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001614 return rc;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001615}
1616
Michal Vasko730dfdf2015-08-11 14:48:05 +02001617/**
Michal Vasko88c29542015-11-27 14:57:53 +01001618 * @brief Resolve a typedef, return only resolved typedefs if derived. Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001619 *
1620 * @param[in] name Typedef name.
Michal Vasko1dca6882015-10-22 14:29:42 +02001621 * @param[in] mod_name Typedef name module name.
1622 * @param[in] module Main module.
1623 * @param[in] parent Parent of the resolved type definition.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001624 * @param[out] ret Pointer to the resolved typedef. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001625 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001626 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001627 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001628int
Michal Vasko1e62a092015-12-01 12:27:20 +01001629resolve_superior_type(const char *name, const char *mod_name, const struct lys_module *module,
1630 const struct lys_node *parent, struct lys_tpdf **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001631{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001632 int i, j;
Radek Krejci1574a8d2015-08-03 14:16:52 +02001633 struct lys_tpdf *tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001634 int tpdf_size;
1635
Michal Vasko1dca6882015-10-22 14:29:42 +02001636 if (!mod_name) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001637 /* no prefix, try built-in types */
1638 for (i = 1; i < LY_DATA_TYPE_COUNT; i++) {
1639 if (!strcmp(ly_types[i].def->name, name)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001640 if (ret) {
1641 *ret = ly_types[i].def;
1642 }
1643 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001644 }
1645 }
1646 } else {
Michal Vasko1dca6882015-10-22 14:29:42 +02001647 if (!strcmp(mod_name, module->name)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001648 /* prefix refers to the current module, ignore it */
Michal Vasko1dca6882015-10-22 14:29:42 +02001649 mod_name = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001650 }
1651 }
1652
Michal Vasko1dca6882015-10-22 14:29:42 +02001653 if (!mod_name && parent) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001654 /* search in local typedefs */
1655 while (parent) {
1656 switch (parent->nodetype) {
Radek Krejci76512572015-08-04 09:47:08 +02001657 case LYS_CONTAINER:
Radek Krejcib8048692015-08-05 13:36:34 +02001658 tpdf_size = ((struct lys_node_container *)parent)->tpdf_size;
1659 tpdf = ((struct lys_node_container *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001660 break;
1661
Radek Krejci76512572015-08-04 09:47:08 +02001662 case LYS_LIST:
Radek Krejcib8048692015-08-05 13:36:34 +02001663 tpdf_size = ((struct lys_node_list *)parent)->tpdf_size;
1664 tpdf = ((struct lys_node_list *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001665 break;
1666
Radek Krejci76512572015-08-04 09:47:08 +02001667 case LYS_GROUPING:
Radek Krejcib8048692015-08-05 13:36:34 +02001668 tpdf_size = ((struct lys_node_grp *)parent)->tpdf_size;
1669 tpdf = ((struct lys_node_grp *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001670 break;
1671
Radek Krejci76512572015-08-04 09:47:08 +02001672 case LYS_RPC:
Radek Krejcib8048692015-08-05 13:36:34 +02001673 tpdf_size = ((struct lys_node_rpc *)parent)->tpdf_size;
1674 tpdf = ((struct lys_node_rpc *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001675 break;
1676
Radek Krejci76512572015-08-04 09:47:08 +02001677 case LYS_NOTIF:
Radek Krejcib8048692015-08-05 13:36:34 +02001678 tpdf_size = ((struct lys_node_notif *)parent)->tpdf_size;
1679 tpdf = ((struct lys_node_notif *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001680 break;
1681
Radek Krejci76512572015-08-04 09:47:08 +02001682 case LYS_INPUT:
1683 case LYS_OUTPUT:
Radek Krejci4608ada2015-08-05 16:04:37 +02001684 tpdf_size = ((struct lys_node_rpc_inout *)parent)->tpdf_size;
1685 tpdf = ((struct lys_node_rpc_inout *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001686 break;
1687
1688 default:
1689 parent = parent->parent;
1690 continue;
1691 }
1692
1693 for (i = 0; i < tpdf_size; i++) {
Michal Vasko88c29542015-11-27 14:57:53 +01001694 if (!strcmp(tpdf[i].name, name) && tpdf[i].type.base) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001695 if (ret) {
1696 *ret = &tpdf[i];
1697 }
1698 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001699 }
1700 }
1701
1702 parent = parent->parent;
1703 }
Radek Krejcic071c542016-01-27 14:57:51 +01001704 } else {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001705 /* get module where to search */
Michal Vaskob6729c62015-10-21 12:09:47 +02001706 module = lys_get_import_module(module, NULL, 0, mod_name, 0);
Michal Vaskoc935fff2015-08-17 14:02:06 +02001707 if (!module) {
1708 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001709 }
1710 }
1711
1712 /* search in top level typedefs */
1713 for (i = 0; i < module->tpdf_size; i++) {
Michal Vasko88c29542015-11-27 14:57:53 +01001714 if (!strcmp(module->tpdf[i].name, name) && module->tpdf[i].type.base) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001715 if (ret) {
1716 *ret = &module->tpdf[i];
1717 }
1718 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001719 }
1720 }
1721
1722 /* search in submodules */
Radek Krejcic071c542016-01-27 14:57:51 +01001723 for (i = 0; i < module->inc_size && module->inc[i].submodule; i++) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001724 for (j = 0; j < module->inc[i].submodule->tpdf_size; j++) {
Michal Vasko88c29542015-11-27 14:57:53 +01001725 if (!strcmp(module->inc[i].submodule->tpdf[j].name, name) && module->inc[i].submodule->tpdf[j].type.base) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001726 if (ret) {
1727 *ret = &module->inc[i].submodule->tpdf[j];
1728 }
1729 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001730 }
1731 }
1732 }
1733
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001734 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001735}
1736
Michal Vasko1dca6882015-10-22 14:29:42 +02001737/**
1738 * @brief Check the default \p value of the \p type. Logs directly.
1739 *
1740 * @param[in] type Type definition to use.
1741 * @param[in] value Default value to check.
1742 * @param[in] first Whether this is the first resolution try. Affects logging.
1743 * @param[in] line Line in the input file.
1744 *
1745 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
1746 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001747static int
Michal Vasko1dca6882015-10-22 14:29:42 +02001748check_default(struct lys_type *type, const char *value, int first, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001749{
Michal Vasko1dca6882015-10-22 14:29:42 +02001750 struct lyd_node_leaf_list node;
Radek Krejci37b756f2016-01-18 10:15:03 +01001751 int ret = EXIT_SUCCESS;
Michal Vasko1dca6882015-10-22 14:29:42 +02001752
1753 /* dummy leaf */
1754 node.value_str = value;
1755 node.value_type = type->base;
Radek Krejci37b756f2016-01-18 10:15:03 +01001756 node.schema = calloc(1, sizeof (struct lys_node_leaf));
Michal Vasko253035f2015-12-17 16:58:13 +01001757 if (!node.schema) {
1758 LOGMEM;
1759 return -1;
1760 }
Michal Vasko1dca6882015-10-22 14:29:42 +02001761 node.schema->name = strdup("default");
Michal Vasko253035f2015-12-17 16:58:13 +01001762 if (!node.schema->name) {
1763 LOGMEM;
1764 return -1;
1765 }
Radek Krejci37b756f2016-01-18 10:15:03 +01001766 memcpy(&((struct lys_node_leaf *)node.schema)->type, type, sizeof *type);
Michal Vasko1dca6882015-10-22 14:29:42 +02001767
Radek Krejci37b756f2016-01-18 10:15:03 +01001768 if (type->base == LY_TYPE_LEAFREF) {
Michal Vasko1dca6882015-10-22 14:29:42 +02001769 if (!type->info.lref.target) {
1770 ret = EXIT_FAILURE;
1771 goto finish;
1772 }
1773 ret = check_default(&type->info.lref.target->type, value, first, line);
1774
1775 } else if ((type->base == LY_TYPE_INST) || (type->base == LY_TYPE_IDENT)) {
1776 /* it was converted to JSON format before, nothing else sensible we can do */
1777
1778 } else {
Radek Krejci37b756f2016-01-18 10:15:03 +01001779 ret = lyp_parse_value(&node, NULL, 1, NULL, line);
Michal Vasko1dca6882015-10-22 14:29:42 +02001780 }
1781
1782finish:
1783 if (node.value_type == LY_TYPE_BITS) {
1784 free(node.value.bit);
1785 }
1786 free((char *)node.schema->name);
1787 free(node.schema);
1788
1789 return ret;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001790}
1791
Michal Vasko730dfdf2015-08-11 14:48:05 +02001792/**
1793 * @brief Check a key for mandatory attributes. Logs directly.
1794 *
1795 * @param[in] key The key to check.
1796 * @param[in] flags What flags to check.
1797 * @param[in] list The list of all the keys.
1798 * @param[in] index Index of the key in the key list.
1799 * @param[in] name The name of the keys.
1800 * @param[in] len The name length.
1801 * @param[in] line The line in the input file.
1802 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001803 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001804 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001805static int
Radek Krejciadb57612016-02-16 13:34:34 +01001806check_key(struct lys_node_list *list, int index, const char *name, int len, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001807{
Radek Krejciadb57612016-02-16 13:34:34 +01001808 struct lys_node_leaf *key = list->keys[index];
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001809 char *dup = NULL;
1810 int j;
1811
1812 /* existence */
1813 if (!key) {
Michal Vaskof02e3742015-08-05 16:27:02 +02001814 if (name[len] != '\0') {
1815 dup = strdup(name);
Michal Vasko253035f2015-12-17 16:58:13 +01001816 if (!dup) {
1817 LOGMEM;
1818 return -1;
1819 }
Michal Vaskof02e3742015-08-05 16:27:02 +02001820 dup[len] = '\0';
1821 name = dup;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001822 }
Radek Krejciadb57612016-02-16 13:34:34 +01001823 LOGVAL(LYE_KEY_MISS, line, LY_VLOG_LYS, list, name);
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02001824 free(dup);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001825 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001826 }
1827
1828 /* uniqueness */
1829 for (j = index - 1; j >= 0; j--) {
Radek Krejciadb57612016-02-16 13:34:34 +01001830 if (key == list->keys[j]) {
1831 LOGVAL(LYE_KEY_DUP, line, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001832 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001833 }
1834 }
1835
1836 /* key is a leaf */
Radek Krejci76512572015-08-04 09:47:08 +02001837 if (key->nodetype != LYS_LEAF) {
Radek Krejciadb57612016-02-16 13:34:34 +01001838 LOGVAL(LYE_KEY_NLEAF, line, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001839 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001840 }
1841
1842 /* type of the leaf is not built-in empty */
1843 if (key->type.base == LY_TYPE_EMPTY) {
Radek Krejciadb57612016-02-16 13:34:34 +01001844 LOGVAL(LYE_KEY_TYPE, line, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001845 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001846 }
1847
1848 /* config attribute is the same as of the list */
Radek Krejciadb57612016-02-16 13:34:34 +01001849 if ((list->flags & LYS_CONFIG_MASK) != (key->flags & LYS_CONFIG_MASK)) {
1850 LOGVAL(LYE_KEY_CONFIG, line, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001851 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001852 }
1853
1854 return EXIT_SUCCESS;
1855}
1856
Michal Vasko730dfdf2015-08-11 14:48:05 +02001857/**
Radek Krejci581ce772015-11-10 17:22:40 +01001858 * @brief Resolve (test the target exists) unique. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001859 *
1860 * @param[in] parent The parent node of the unique structure.
1861 * @param[in] uniq_str The value of the unique node.
Michal Vasko184521f2015-09-24 13:14:26 +02001862 * @param[in] first Whether this is the first resolution try. Affects logging.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001863 * @param[in] line The line in the input file.
1864 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001865 * @return EXIT_SUCCESS on succes, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001866 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001867int
Radek Krejci581ce772015-11-10 17:22:40 +01001868resolve_unique(struct lys_node *parent, const char *uniq_str, int first, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001869{
Radek Krejci581ce772015-11-10 17:22:40 +01001870 int rc;
Michal Vasko1e62a092015-12-01 12:27:20 +01001871 const struct lys_node *leaf = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001872
Michal Vasko3edeaf72016-02-11 13:17:43 +01001873 rc = resolve_descendant_schema_nodeid(uniq_str, parent->child, LYS_LEAF, &leaf);
Michal Vasko9bb061b2016-02-12 11:00:19 +01001874 if (rc || !leaf) {
Radek Krejci581ce772015-11-10 17:22:40 +01001875 if ((rc == -1) || !first) {
Radek Krejciadb57612016-02-16 13:34:34 +01001876 LOGVAL(LYE_INARG, line, LY_VLOG_LYS, parent, uniq_str, "unique");
Radek Krejci581ce772015-11-10 17:22:40 +01001877 if (rc == EXIT_FAILURE) {
Radek Krejciadb57612016-02-16 13:34:34 +01001878 LOGVAL(LYE_SPEC, 0, 0, NULL, "Target leaf not found.");
Radek Krejci581ce772015-11-10 17:22:40 +01001879 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001880 }
Radek Krejci581ce772015-11-10 17:22:40 +01001881 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001882 }
Michal Vasko9bb061b2016-02-12 11:00:19 +01001883 if (leaf->nodetype != LYS_LEAF) {
Radek Krejciadb57612016-02-16 13:34:34 +01001884 LOGVAL(LYE_INARG, line, LY_VLOG_LYS, parent, uniq_str, "unique");
1885 LOGVAL(LYE_SPEC, 0, 0, NULL, "Target is not a leaf.");
Radek Krejci581ce772015-11-10 17:22:40 +01001886 rc = -1;
1887 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001888 }
1889
Radek Krejcicf509982015-12-15 09:22:44 +01001890 /* check status */
Radek Krejciadb57612016-02-16 13:34:34 +01001891 if (lyp_check_status(parent->flags, parent->module, parent->name, leaf->flags, leaf->module, leaf->name,
1892 line, leaf)) {
Radek Krejcicf509982015-12-15 09:22:44 +01001893 return -1;
1894 }
1895
Radek Krejcica7efb72016-01-18 13:06:01 +01001896 /* set leaf's unique flag */
1897 ((struct lys_node_leaf *)leaf)->flags |= LYS_UNIQUE;
1898
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001899 return EXIT_SUCCESS;
1900
1901error:
1902
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001903 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001904}
1905
Michal Vasko730dfdf2015-08-11 14:48:05 +02001906/**
Michal Vasko730dfdf2015-08-11 14:48:05 +02001907 * @brief Resolve (find) a feature definition. Logs directly.
1908 *
1909 * @param[in] name Feature name.
1910 * @param[in] module Module to search in.
Michal Vasko184521f2015-09-24 13:14:26 +02001911 * @param[in] first Whether this is the first resolution try. Affects logging.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001912 * @param[in] line The line in the input file.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001913 * @param[out] ret Pointer to the resolved feature. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001914 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001915 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001916 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001917static int
Michal Vasko1e62a092015-12-01 12:27:20 +01001918resolve_feature(const char *id, const struct lys_module *module, int first, uint32_t line, struct lys_feature **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001919{
Michal Vasko2d851a92015-10-20 16:16:36 +02001920 const char *mod_name, *name;
Michal Vasko2d851a92015-10-20 16:16:36 +02001921 int mod_name_len, nam_len, i, j;
Radek Krejcicf509982015-12-15 09:22:44 +01001922 struct lys_node *node;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001923
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001924 assert(id);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001925 assert(module);
1926
1927 /* check prefix */
Michal Vasko2d851a92015-10-20 16:16:36 +02001928 if ((i = parse_node_identifier(id, &mod_name, &mod_name_len, &name, &nam_len)) < 1) {
Radek Krejciadb57612016-02-16 13:34:34 +01001929 LOGVAL(LYE_INCHAR, line, 0, NULL, id[-i], &id[-i]);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001930 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001931 }
1932
Radek Krejcic071c542016-01-27 14:57:51 +01001933 module = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
1934 if (!module) {
1935 /* identity refers unknown data model */
Radek Krejciadb57612016-02-16 13:34:34 +01001936 LOGVAL(LYE_INMOD_LEN, line, 0, NULL, mod_name_len, mod_name);
Radek Krejcic071c542016-01-27 14:57:51 +01001937 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001938 }
1939
Radek Krejcic071c542016-01-27 14:57:51 +01001940 /* search in the identified module ... */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001941 for (j = 0; j < module->features_size; j++) {
1942 if (!strcmp(name, module->features[j].name)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001943 if (ret) {
Radek Krejcicf509982015-12-15 09:22:44 +01001944 /* check status */
1945 node = (struct lys_node *)*ret;
Radek Krejcic6556022016-01-27 15:16:45 +01001946 if (lyp_check_status(node->flags, node->module, node->name, module->features[j].flags,
Radek Krejciadb57612016-02-16 13:34:34 +01001947 module->features[j].module, module->features[j].name, line, node)) {
Radek Krejcicf509982015-12-15 09:22:44 +01001948 return -1;
1949 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001950 *ret = &module->features[j];
1951 }
1952 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001953 }
1954 }
Radek Krejcic071c542016-01-27 14:57:51 +01001955 /* ... and all its submodules */
Michal Vasko27ab8222016-02-12 09:33:52 +01001956 for (i = 0; i < module->inc_size; i++) {
1957 if (!module->inc[i].submodule) {
1958 /* not yet resolved */
1959 continue;
1960 }
Radek Krejcic071c542016-01-27 14:57:51 +01001961 for (j = 0; j < module->inc[i].submodule->features_size; j++) {
1962 if (!strcmp(name, module->inc[i].submodule->features[j].name)) {
1963 if (ret) {
1964 /* check status */
1965 node = (struct lys_node *)*ret;
Radek Krejcic6556022016-01-27 15:16:45 +01001966 if (lyp_check_status(node->flags, node->module, node->name,
Radek Krejcic071c542016-01-27 14:57:51 +01001967 module->inc[i].submodule->features[j].flags,
1968 module->inc[i].submodule->features[j].module,
Radek Krejciadb57612016-02-16 13:34:34 +01001969 module->inc[i].submodule->features[j].name, line, node)) {
Radek Krejcic071c542016-01-27 14:57:51 +01001970 return -1;
1971 }
1972 *ret = &(module->inc[i].submodule->features[j]);
1973 }
1974 return EXIT_SUCCESS;
1975 }
1976 }
1977 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001978
1979 /* not found */
Michal Vasko184521f2015-09-24 13:14:26 +02001980 if (!first) {
Radek Krejciadb57612016-02-16 13:34:34 +01001981 LOGVAL(LYE_INRESOLV, line, 0, NULL, "feature", id);
Michal Vasko184521f2015-09-24 13:14:26 +02001982 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001983 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02001984}
1985
Michal Vasko23b61ec2015-08-19 11:19:50 +02001986/* ignores line */
1987static void
1988unres_data_del(struct unres_data *unres, uint32_t i)
1989{
1990 /* there are items after the one deleted */
1991 if (i+1 < unres->count) {
1992 /* we only move the data, memory is left allocated, why bother */
Michal Vaskocf024702015-10-08 15:01:42 +02001993 memmove(&unres->node[i], &unres->node[i+1], (unres->count-(i+1)) * sizeof *unres->node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02001994
1995 /* deleting the last item */
1996 } else if (i == 0) {
Michal Vaskocf024702015-10-08 15:01:42 +02001997 free(unres->node);
1998 unres->node = NULL;
Michal Vasko23b61ec2015-08-19 11:19:50 +02001999 }
2000
2001 /* if there are no items after and it is not the last one, just move the counter */
2002 --unres->count;
2003}
2004
Michal Vasko0491ab32015-08-19 14:28:29 +02002005/**
2006 * @brief Resolve (find) a data node from a specific module. Does not log.
2007 *
2008 * @param[in] mod Module to search in.
2009 * @param[in] name Name of the data node.
2010 * @param[in] nam_len Length of the name.
2011 * @param[in] start Data node to start the search from.
2012 * @param[in,out] parents Resolved nodes. If there are some parents,
2013 * they are replaced (!!) with the resolvents.
2014 *
2015 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference.
2016 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002017static int
Michal Vasko1e62a092015-12-01 12:27:20 +01002018resolve_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 +02002019{
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002020 struct lyd_node *node;
Radek Krejcic5090c32015-08-12 09:46:19 +02002021 int flag;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002022 uint32_t i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002023
Michal Vasko23b61ec2015-08-19 11:19:50 +02002024 if (!parents->count) {
2025 parents->count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02002026 parents->node = malloc(sizeof *parents->node);
Michal Vasko253035f2015-12-17 16:58:13 +01002027 if (!parents->node) {
2028 LOGMEM;
2029 return EXIT_FAILURE;
2030 }
Michal Vaskocf024702015-10-08 15:01:42 +02002031 parents->node[0] = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002032 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02002033 for (i = 0; i < parents->count;) {
Michal Vaskocf024702015-10-08 15:01:42 +02002034 if (parents->node[i] && (parents->node[i]->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYXML))) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002035 /* skip */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002036 ++i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002037 continue;
2038 }
2039 flag = 0;
Michal Vaskocf024702015-10-08 15:01:42 +02002040 LY_TREE_FOR(parents->node[i] ? parents->node[i]->child : start, node) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002041 if (node->schema->module == mod && !strncmp(node->schema->name, name, nam_len)
2042 && node->schema->name[nam_len] == '\0') {
2043 /* matching target */
2044 if (!flag) {
Michal Vasko9a47e122015-09-03 14:26:32 +02002045 /* put node instead of the current parent */
Michal Vaskocf024702015-10-08 15:01:42 +02002046 parents->node[i] = node;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002047 flag = 1;
2048 } else {
Michal Vasko9a47e122015-09-03 14:26:32 +02002049 /* multiple matching, so create a new node */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002050 ++parents->count;
Michal Vasko253035f2015-12-17 16:58:13 +01002051 parents->node = ly_realloc(parents->node, parents->count * sizeof *parents->node);
2052 if (!parents->node) {
2053 return EXIT_FAILURE;
2054 }
Michal Vaskocf024702015-10-08 15:01:42 +02002055 parents->node[parents->count-1] = node;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002056 ++i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002057 }
2058 }
2059 }
Radek Krejcic5090c32015-08-12 09:46:19 +02002060
2061 if (!flag) {
2062 /* remove item from the parents list */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002063 unres_data_del(parents, i);
Radek Krejcic5090c32015-08-12 09:46:19 +02002064 } else {
Michal Vasko23b61ec2015-08-19 11:19:50 +02002065 ++i;
Radek Krejcic5090c32015-08-12 09:46:19 +02002066 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002067 }
2068
Michal Vasko0491ab32015-08-19 14:28:29 +02002069 return parents->count ? EXIT_SUCCESS : EXIT_FAILURE;
Radek Krejcic5090c32015-08-12 09:46:19 +02002070}
2071
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002072/**
2073 * @brief Resolve (find) a data node. Does not log.
2074 *
Radek Krejci581ce772015-11-10 17:22:40 +01002075 * @param[in] mod_name Module name of the data node.
2076 * @param[in] mod_name_len Length of the module name.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002077 * @param[in] name Name of the data node.
2078 * @param[in] nam_len Length of the name.
2079 * @param[in] start Data node to start the search from.
2080 * @param[in,out] parents Resolved nodes. If there are some parents,
2081 * they are replaced (!!) with the resolvents.
2082 *
Michal Vasko0491ab32015-08-19 14:28:29 +02002083 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 otherwise.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002084 */
Radek Krejcic5090c32015-08-12 09:46:19 +02002085static int
Radek Krejci581ce772015-11-10 17:22:40 +01002086resolve_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 +02002087 struct unres_data *parents)
Radek Krejcic5090c32015-08-12 09:46:19 +02002088{
Michal Vasko1e62a092015-12-01 12:27:20 +01002089 const struct lys_module *mod;
Michal Vasko31fc3672015-10-21 12:08:13 +02002090 char *str;
Radek Krejcic5090c32015-08-12 09:46:19 +02002091
Michal Vasko23b61ec2015-08-19 11:19:50 +02002092 assert(start);
2093
Michal Vasko31fc3672015-10-21 12:08:13 +02002094 if (mod_name) {
2095 /* we have mod_name, find appropriate module */
2096 str = strndup(mod_name, mod_name_len);
Michal Vasko253035f2015-12-17 16:58:13 +01002097 if (!str) {
2098 LOGMEM;
2099 return -1;
2100 }
Michal Vasko31fc3672015-10-21 12:08:13 +02002101 mod = ly_ctx_get_module(start->schema->module->ctx, str, NULL);
2102 free(str);
Radek Krejcic5090c32015-08-12 09:46:19 +02002103 if (!mod) {
2104 /* invalid prefix */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002105 return -1;
Radek Krejcic5090c32015-08-12 09:46:19 +02002106 }
2107 } else {
2108 /* no prefix, module is the same as of current node */
2109 mod = start->schema->module;
2110 }
2111
2112 return resolve_data(mod, name, name_len, start, parents);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002113}
2114
Michal Vasko730dfdf2015-08-11 14:48:05 +02002115/**
Michal Vaskof39142b2015-10-21 11:40:05 +02002116 * @brief Resolve a path predicate (leafref) in JSON data context. Logs directly
Michal Vaskod9173342015-08-17 14:35:36 +02002117 * only specific errors, general no-resolvent error is left to the caller,
2118 * but line fail is always displayed.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002119 *
Michal Vaskobb211122015-08-19 14:03:11 +02002120 * @param[in] pred Predicate to use.
Michal Vasko184521f2015-09-24 13:14:26 +02002121 * @param[in] first Whether this is the first resolution try. Affects logging.
Michal Vasko0491ab32015-08-19 14:28:29 +02002122 * @param[in] line Line in the input file.
Radek Krejciadb57612016-02-16 13:34:34 +01002123 * @param[in] node Node from which the predicate is being resolved
Michal Vasko730dfdf2015-08-11 14:48:05 +02002124 * @param[in,out] node_match Nodes satisfying the restriction
2125 * without the predicate. Nodes not
2126 * satisfying the predicate are removed.
Michal Vasko0491ab32015-08-19 14:28:29 +02002127 * @param[out] parsed Number of characters parsed, negative on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002128 *
Michal Vasko0491ab32015-08-19 14:28:29 +02002129 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002130 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002131static int
Radek Krejciadb57612016-02-16 13:34:34 +01002132resolve_path_predicate_data(const char *pred, int first, uint32_t line,struct lyd_node *node,
2133 struct unres_data *node_match, int *parsed)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002134{
Michal Vasko730dfdf2015-08-11 14:48:05 +02002135 /* ... /node[source = destination] ... */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002136 struct unres_data source_match, dest_match;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002137 const char *path_key_expr, *source, *sour_pref, *dest, *dest_pref;
Michal Vasko0491ab32015-08-19 14:28:29 +02002138 int pke_len, sour_len, sour_pref_len, dest_len, dest_pref_len, parsed_loc = 0, pke_parsed = 0;
2139 int has_predicate, dest_parent_times, i, rc;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002140 uint32_t j;
2141
2142 source_match.count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02002143 source_match.node = malloc(sizeof *source_match.node);
Michal Vasko253035f2015-12-17 16:58:13 +01002144 if (!source_match.node) {
2145 LOGMEM;
2146 return -1;
2147 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02002148 dest_match.count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02002149 dest_match.node = malloc(sizeof *dest_match.node);
Michal Vasko253035f2015-12-17 16:58:13 +01002150 if (!dest_match.node) {
2151 LOGMEM;
2152 return -1;
2153 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002154
2155 do {
2156 if ((i = parse_path_predicate(pred, &sour_pref, &sour_pref_len, &source, &sour_len, &path_key_expr,
2157 &pke_len, &has_predicate)) < 1) {
Radek Krejciadb57612016-02-16 13:34:34 +01002158 LOGVAL(LYE_INCHAR, line, LY_VLOG_LYD, node, pred[-i], &pred[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02002159 rc = -1;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002160 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002161 }
Michal Vasko0491ab32015-08-19 14:28:29 +02002162 parsed_loc += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002163 pred += i;
2164
Michal Vasko23b61ec2015-08-19 11:19:50 +02002165 for (j = 0; j < node_match->count;) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002166 /* source */
Michal Vaskocf024702015-10-08 15:01:42 +02002167 source_match.node[0] = node_match->node[j];
Michal Vasko23b61ec2015-08-19 11:19:50 +02002168
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002169 /* must be leaf (key of a list) */
Radek Krejci581ce772015-11-10 17:22:40 +01002170 if ((rc = resolve_data_node(sour_pref, sour_pref_len, source, sour_len, node_match->node[j],
Michal Vaskocf024702015-10-08 15:01:42 +02002171 &source_match)) || (source_match.count != 1) || (source_match.node[0]->schema->nodetype != LYS_LEAF)) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002172 /* general error, the one written later will suffice */
Michal Vasko184521f2015-09-24 13:14:26 +02002173 if ((rc == -1) || !first) {
Radek Krejciadb57612016-02-16 13:34:34 +01002174 LOGVAL(LYE_LINE, line, 0, NULL);
Michal Vasko184521f2015-09-24 13:14:26 +02002175 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02002176 i = 0;
2177 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002178 }
2179
2180 /* destination */
Michal Vaskocf024702015-10-08 15:01:42 +02002181 dest_match.node[0] = node_match->node[j];
Michal Vasko23b61ec2015-08-19 11:19:50 +02002182 dest_parent_times = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002183 if ((i = parse_path_key_expr(path_key_expr, &dest_pref, &dest_pref_len, &dest, &dest_len,
2184 &dest_parent_times)) < 1) {
Radek Krejciadb57612016-02-16 13:34:34 +01002185 LOGVAL(LYE_INCHAR, line, LY_VLOG_LYD, node, path_key_expr[-i], &path_key_expr[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02002186 rc = -1;
2187 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002188 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02002189 pke_parsed = i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002190 for (i = 0; i < dest_parent_times; ++i) {
Michal Vaskocf024702015-10-08 15:01:42 +02002191 dest_match.node[0] = dest_match.node[0]->parent;
2192 if (!dest_match.node[0]) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002193 /* general error, the one written later will suffice */
Michal Vasko184521f2015-09-24 13:14:26 +02002194 if (!first) {
Radek Krejciadb57612016-02-16 13:34:34 +01002195 LOGVAL(LYE_LINE, line, 0, NULL);
Michal Vasko184521f2015-09-24 13:14:26 +02002196 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02002197 i = 0;
Michal Vasko0491ab32015-08-19 14:28:29 +02002198 rc = EXIT_FAILURE;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002199 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002200 }
2201 }
2202 while (1) {
Radek Krejci581ce772015-11-10 17:22:40 +01002203 if ((rc = resolve_data_node(dest_pref, dest_pref_len, dest, dest_len, dest_match.node[0],
Michal Vasko0491ab32015-08-19 14:28:29 +02002204 &dest_match)) || (dest_match.count != 1)) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002205 /* general error, the one written later will suffice */
Michal Vasko184521f2015-09-24 13:14:26 +02002206 if ((rc == -1) || !first) {
Radek Krejciadb57612016-02-16 13:34:34 +01002207 LOGVAL(LYE_LINE, line, 0, NULL);
Michal Vasko184521f2015-09-24 13:14:26 +02002208 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02002209 i = 0;
2210 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002211 }
2212
2213 if (pke_len == pke_parsed) {
2214 break;
2215 }
Michal Vasko1f76a282015-08-04 16:16:53 +02002216 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 +02002217 &dest_parent_times)) < 1) {
Radek Krejciadb57612016-02-16 13:34:34 +01002218 LOGVAL(LYE_INCHAR, line, LY_VLOG_LYD, node, path_key_expr[-i], &path_key_expr[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02002219 rc = -1;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002220 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002221 }
2222 pke_parsed += i;
2223 }
2224
2225 /* check match between source and destination nodes */
Michal Vaskocf024702015-10-08 15:01:42 +02002226 if (((struct lys_node_leaf *)source_match.node[0]->schema)->type.base
2227 != ((struct lys_node_leaf *)dest_match.node[0]->schema)->type.base) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002228 goto remove_leafref;
2229 }
2230
Michal Vasko83a6c462015-10-08 16:43:53 +02002231 if (((struct lyd_node_leaf_list *)source_match.node[0])->value_str
2232 != ((struct lyd_node_leaf_list *)dest_match.node[0])->value_str) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002233 goto remove_leafref;
2234 }
2235
2236 /* leafref is ok, continue check with next leafref */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002237 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002238 continue;
2239
2240remove_leafref:
2241 /* does not fulfill conditions, remove leafref record */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002242 unres_data_del(node_match, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002243 }
2244 } while (has_predicate);
2245
Michal Vaskocf024702015-10-08 15:01:42 +02002246 free(source_match.node);
2247 free(dest_match.node);
Michal Vasko0491ab32015-08-19 14:28:29 +02002248 if (parsed) {
2249 *parsed = parsed_loc;
2250 }
2251 return EXIT_SUCCESS;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002252
2253error:
2254
2255 if (source_match.count) {
Michal Vaskocf024702015-10-08 15:01:42 +02002256 free(source_match.node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02002257 }
2258 if (dest_match.count) {
Michal Vaskocf024702015-10-08 15:01:42 +02002259 free(dest_match.node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02002260 }
Michal Vasko0491ab32015-08-19 14:28:29 +02002261 if (parsed) {
2262 *parsed = -parsed_loc+i;
2263 }
2264 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002265}
2266
Michal Vasko730dfdf2015-08-11 14:48:05 +02002267/**
Michal Vaskof39142b2015-10-21 11:40:05 +02002268 * @brief Resolve a path (leafref) in JSON data context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002269 *
Michal Vaskocf024702015-10-08 15:01:42 +02002270 * @param[in] node Leafref data node.
Michal Vasko23b61ec2015-08-19 11:19:50 +02002271 * @param[in] path Path of the leafref.
Michal Vasko184521f2015-09-24 13:14:26 +02002272 * @param[in] first Whether this is the first resolution try. Affects logging.
Michal Vasko23b61ec2015-08-19 11:19:50 +02002273 * @param[in] line Line in the input file.
Michal Vaskobb211122015-08-19 14:03:11 +02002274 * @param[out] ret Matching nodes. Expects an empty, but allocated structure. Lines left untouched.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002275 *
Michal Vasko0491ab32015-08-19 14:28:29 +02002276 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 otherwise.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002277 */
Michal Vasko184521f2015-09-24 13:14:26 +02002278static int
Michal Vaskocf024702015-10-08 15:01:42 +02002279resolve_path_arg_data(struct lyd_node *node, const char *path, int first, uint32_t line, struct unres_data *ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002280{
Radek Krejci71b795b2015-08-10 16:20:39 +02002281 struct lyd_node *data = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002282 const char *prefix, *name;
Michal Vasko0491ab32015-08-19 14:28:29 +02002283 int pref_len, nam_len, has_predicate, parent_times, i, parsed, rc;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002284 uint32_t j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002285
Michal Vaskocf024702015-10-08 15:01:42 +02002286 assert(node && path && ret && !ret->count);
Michal Vasko23b61ec2015-08-19 11:19:50 +02002287
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002288 parent_times = 0;
Michal Vaskod9173342015-08-17 14:35:36 +02002289 parsed = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002290
2291 /* searching for nodeset */
2292 do {
2293 if ((i = parse_path_arg(path, &prefix, &pref_len, &name, &nam_len, &parent_times, &has_predicate)) < 1) {
Radek Krejciadb57612016-02-16 13:34:34 +01002294 LOGVAL(LYE_INCHAR, line, LY_VLOG_LYD, node, path[-i], &path[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02002295 rc = -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002296 goto error;
2297 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002298 path += i;
Michal Vaskod9173342015-08-17 14:35:36 +02002299 parsed += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002300
Michal Vasko23b61ec2015-08-19 11:19:50 +02002301 if (!ret->count) {
Michal Vasko8bcdf292015-08-19 14:04:43 +02002302 if (parent_times != -1) {
2303 ret->count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02002304 ret->node = calloc(1, sizeof *ret->node);
Michal Vasko253035f2015-12-17 16:58:13 +01002305 if (!ret->node) {
2306 LOGMEM;
Radek Krejci50501732016-01-07 13:06:39 +01002307 rc = -1;
Michal Vasko253035f2015-12-17 16:58:13 +01002308 goto error;
2309 }
Michal Vasko8bcdf292015-08-19 14:04:43 +02002310 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002311 for (i = 0; i < parent_times; ++i) {
2312 /* relative path */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002313 if (!ret->count) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002314 /* error, too many .. */
Radek Krejciadb57612016-02-16 13:34:34 +01002315 LOGVAL(LYE_INVAL, line, LY_VLOG_LYD, node, path, node->schema->name);
Michal Vasko0491ab32015-08-19 14:28:29 +02002316 rc = -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002317 goto error;
Michal Vaskocf024702015-10-08 15:01:42 +02002318 } else if (!ret->node[0]) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002319 /* first .. */
Michal Vaskocf024702015-10-08 15:01:42 +02002320 data = ret->node[0] = node->parent;
2321 } else if (!ret->node[0]->parent) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002322 /* we are in root */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002323 ret->count = 0;
Michal Vaskocf024702015-10-08 15:01:42 +02002324 free(ret->node);
2325 ret->node = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002326 } else {
2327 /* multiple .. */
Michal Vaskocf024702015-10-08 15:01:42 +02002328 data = ret->node[0] = ret->node[0]->parent;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002329 }
2330 }
2331
2332 /* absolute path */
2333 if (parent_times == -1) {
Michal Vaskocf024702015-10-08 15:01:42 +02002334 for (data = node; data->parent; data = data->parent);
Michal Vaskodb9323c2015-10-16 10:32:44 +02002335 /* we're still parsing it and the pointer is not correct yet */
Michal Vasko8bcdf292015-08-19 14:04:43 +02002336 if (data->prev) {
2337 for (; data->prev->next; data = data->prev);
2338 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002339 }
2340 }
2341
2342 /* node identifier */
Radek Krejci581ce772015-11-10 17:22:40 +01002343 if ((rc = resolve_data_node(prefix, pref_len, name, nam_len, data, ret))) {
Michal Vasko184521f2015-09-24 13:14:26 +02002344 if ((rc == -1) || !first) {
Radek Krejciadb57612016-02-16 13:34:34 +01002345 LOGVAL(LYE_INELEM_LEN, line, LY_VLOG_LYD, node, nam_len, name);
Michal Vasko184521f2015-09-24 13:14:26 +02002346 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002347 goto error;
2348 }
2349
2350 if (has_predicate) {
2351 /* we have predicate, so the current results must be lists */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002352 for (j = 0; j < ret->count;) {
Michal Vaskocf024702015-10-08 15:01:42 +02002353 if (ret->node[j]->schema->nodetype == LYS_LIST &&
2354 ((struct lys_node_list *)ret->node[0]->schema)->keys) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002355 /* leafref is ok, continue check with next leafref */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002356 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002357 continue;
2358 }
2359
2360 /* does not fulfill conditions, remove leafref record */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002361 unres_data_del(ret, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002362 }
Radek Krejciadb57612016-02-16 13:34:34 +01002363 if ((rc = resolve_path_predicate_data(path, first, line, node, ret, &i))) {
Michal Vaskod9173342015-08-17 14:35:36 +02002364 /* line was already displayed */
Michal Vasko184521f2015-09-24 13:14:26 +02002365 if ((rc == -1) || !first) {
Radek Krejciadb57612016-02-16 13:34:34 +01002366 LOGVAL(LYE_NORESOLV, 0, LY_VLOG_LYD, node, path);
Michal Vasko184521f2015-09-24 13:14:26 +02002367 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002368 goto error;
2369 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002370 path += i;
Michal Vaskod9173342015-08-17 14:35:36 +02002371 parsed += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002372
Michal Vasko23b61ec2015-08-19 11:19:50 +02002373 if (!ret->count) {
Michal Vasko184521f2015-09-24 13:14:26 +02002374 if (!first) {
Radek Krejciadb57612016-02-16 13:34:34 +01002375 LOGVAL(LYE_NORESOLV, line, LY_VLOG_LYD, node, path-parsed);
Michal Vasko184521f2015-09-24 13:14:26 +02002376 }
Michal Vasko0491ab32015-08-19 14:28:29 +02002377 rc = EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002378 goto error;
2379 }
2380 }
2381 } while (path[0] != '\0');
2382
Michal Vaskof02e3742015-08-05 16:27:02 +02002383 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002384
2385error:
2386
Michal Vaskocf024702015-10-08 15:01:42 +02002387 free(ret->node);
2388 ret->node = NULL;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002389 ret->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002390
Michal Vasko0491ab32015-08-19 14:28:29 +02002391 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002392}
2393
Michal Vasko730dfdf2015-08-11 14:48:05 +02002394/**
Michal Vaskof39142b2015-10-21 11:40:05 +02002395 * @brief Resolve a path (leafref) predicate in JSON schema context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002396 *
Michal Vaskobb211122015-08-19 14:03:11 +02002397 * @param[in] path Path to use.
Radek Krejciadb57612016-02-16 13:34:34 +01002398 * @param[in] context_node Predicate context node (where the predicate is placed).
2399 * @param[in] parent Path context node (where the path begins/is placed).
Michal Vasko184521f2015-09-24 13:14:26 +02002400 * @param[in] first Whether this is the first resolution try. Affects logging.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002401 * @param[in] line Line in the input file.
2402 *
Michal Vasko184521f2015-09-24 13:14:26 +02002403 * @return 0 on forward reference, otherwise the number
2404 * of characters successfully parsed,
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002405 * positive on success, negative on failure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002406 */
Michal Vasko1f76a282015-08-04 16:16:53 +02002407static int
Radek Krejciadb57612016-02-16 13:34:34 +01002408resolve_path_predicate_schema(const char *path, const struct lys_node *context_node,
2409 struct lys_node *parent, int first, uint32_t line)
Michal Vasko1f76a282015-08-04 16:16:53 +02002410{
Michal Vasko1e62a092015-12-01 12:27:20 +01002411 const struct lys_node *src_node, *dst_node;
Michal Vasko1f76a282015-08-04 16:16:53 +02002412 const char *path_key_expr, *source, *sour_pref, *dest, *dest_pref;
2413 int pke_len, sour_len, sour_pref_len, dest_len, dest_pref_len, parsed = 0, pke_parsed = 0;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002414 int has_predicate, dest_parent_times = 0, i, rc;
Michal Vasko1f76a282015-08-04 16:16:53 +02002415
2416 do {
Michal Vasko730dfdf2015-08-11 14:48:05 +02002417 if ((i = parse_path_predicate(path, &sour_pref, &sour_pref_len, &source, &sour_len, &path_key_expr,
Michal Vasko1f76a282015-08-04 16:16:53 +02002418 &pke_len, &has_predicate)) < 1) {
Radek Krejciadb57612016-02-16 13:34:34 +01002419 LOGVAL(LYE_INCHAR, line, parent ? LY_VLOG_LYS : 0, parent, path[-i], path-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02002420 return -parsed+i;
2421 }
2422 parsed += i;
Michal Vasko730dfdf2015-08-11 14:48:05 +02002423 path += i;
Michal Vasko1f76a282015-08-04 16:16:53 +02002424
Michal Vasko58090902015-08-13 14:04:15 +02002425 /* source (must be leaf) */
Michal Vasko36cbaa42015-12-14 13:15:48 +01002426 if (!sour_pref) {
Radek Krejciadb57612016-02-16 13:34:34 +01002427 sour_pref = context_node->module->name;
Michal Vasko36cbaa42015-12-14 13:15:48 +01002428 }
Radek Krejciadb57612016-02-16 13:34:34 +01002429 rc = lys_get_sibling(context_node->child, sour_pref, sour_pref_len, source, sour_len,
Michal Vasko165dc4a2015-10-23 09:44:27 +02002430 LYS_LEAF | LYS_AUGMENT, &src_node);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002431 if (rc) {
Michal Vasko184521f2015-09-24 13:14:26 +02002432 if ((rc == -1) || !first) {
Radek Krejciadb57612016-02-16 13:34:34 +01002433 LOGVAL(LYE_NORESOLV, line, parent ? LY_VLOG_LYS : 0, parent, path-parsed);
Michal Vasko184521f2015-09-24 13:14:26 +02002434 }
2435 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02002436 }
2437
2438 /* destination */
2439 if ((i = parse_path_key_expr(path_key_expr, &dest_pref, &dest_pref_len, &dest, &dest_len,
2440 &dest_parent_times)) < 1) {
Radek Krejciadb57612016-02-16 13:34:34 +01002441 LOGVAL(LYE_INCHAR, line, parent ? LY_VLOG_LYS : 0, parent, path_key_expr[-i], path_key_expr-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02002442 return -parsed;
2443 }
2444 pke_parsed += i;
2445
Radek Krejciadb57612016-02-16 13:34:34 +01002446 /* parent is actually the parent of this leaf, so skip the first ".." */
2447 for (i = 0, dst_node = parent; i < dest_parent_times; ++i) {
Michal Vasko1f76a282015-08-04 16:16:53 +02002448 if (!dst_node) {
Radek Krejciadb57612016-02-16 13:34:34 +01002449 LOGVAL(LYE_NORESOLV, line, parent ? LY_VLOG_LYS : 0, parent, path_key_expr);
Michal Vasko184521f2015-09-24 13:14:26 +02002450 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02002451 }
Radek Krejciadb57612016-02-16 13:34:34 +01002452 dst_node = dst_node->parent;
Michal Vasko1f76a282015-08-04 16:16:53 +02002453 }
2454 while (1) {
Michal Vasko36cbaa42015-12-14 13:15:48 +01002455 if (!dest_pref) {
2456 dest_pref = dst_node->module->name;
2457 }
2458 rc = lys_get_sibling(dst_node->child, dest_pref, dest_pref_len, dest, dest_len,
Michal Vasko165dc4a2015-10-23 09:44:27 +02002459 LYS_CONTAINER | LYS_LIST | LYS_LEAF | LYS_AUGMENT, &dst_node);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002460 if (rc) {
Michal Vasko184521f2015-09-24 13:14:26 +02002461 if ((rc == -1) || !first) {
Radek Krejciadb57612016-02-16 13:34:34 +01002462 LOGVAL(LYE_NORESOLV, line, parent ? LY_VLOG_LYS : 0, parent, path_key_expr);
Michal Vasko184521f2015-09-24 13:14:26 +02002463 }
2464 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02002465 }
2466
2467 if (pke_len == pke_parsed) {
2468 break;
2469 }
2470
2471 if ((i = parse_path_key_expr(path_key_expr+pke_parsed, &dest_pref, &dest_pref_len, &dest, &dest_len,
2472 &dest_parent_times)) < 1) {
Radek Krejciadb57612016-02-16 13:34:34 +01002473 LOGVAL(LYE_INCHAR, line, parent ? LY_VLOG_LYS : 0, parent,
2474 (path_key_expr+pke_parsed)[-i], (path_key_expr+pke_parsed)-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02002475 return -parsed;
2476 }
2477 pke_parsed += i;
2478 }
2479
2480 /* check source - dest match */
Michal Vasko184521f2015-09-24 13:14:26 +02002481 if (dst_node->nodetype != LYS_LEAF) {
Radek Krejciadb57612016-02-16 13:34:34 +01002482 LOGVAL(LYE_NORESOLV, line, parent ? LY_VLOG_LYS : 0, parent, path-parsed);
2483 LOGVAL(LYE_SPEC, 0, 0, NULL, "Destination node is not a leaf, but %s.", strnodetype(dst_node->nodetype));
Michal Vasko184521f2015-09-24 13:14:26 +02002484 return -parsed;
2485 }
Michal Vasko1f76a282015-08-04 16:16:53 +02002486 } while (has_predicate);
2487
2488 return parsed;
2489}
2490
Michal Vasko730dfdf2015-08-11 14:48:05 +02002491/**
Michal Vaskof39142b2015-10-21 11:40:05 +02002492 * @brief Resolve a path (leafref) in JSON schema context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002493 *
Michal Vaskobb211122015-08-19 14:03:11 +02002494 * @param[in] path Path to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002495 * @param[in] parent_node Parent of the leafref.
Radek Krejci2f12f852016-01-08 12:59:57 +01002496 * @param[in] parent_tpdf Flag if the parent node is actually typedef, in that case the path
2497 * has to contain absolute path
Michal Vasko184521f2015-09-24 13:14:26 +02002498 * @param[in] first Whether this is the first resolution try. Affects logging.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002499 * @param[in] line Line in the input file.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002500 * @param[out] ret Pointer to the resolved schema node. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002501 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002502 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002503 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002504static int
Radek Krejciadb57612016-02-16 13:34:34 +01002505resolve_path_arg_schema(const char *path, struct lys_node *parent, int parent_tpdf, int first, uint32_t line,
Michal Vasko36cbaa42015-12-14 13:15:48 +01002506 const struct lys_node **ret)
Michal Vasko1f76a282015-08-04 16:16:53 +02002507{
Michal Vasko1e62a092015-12-01 12:27:20 +01002508 const struct lys_node *node;
Radek Krejcic071c542016-01-27 14:57:51 +01002509 const struct lys_module *mod;
Michal Vasko1f76a282015-08-04 16:16:53 +02002510 const char *id, *prefix, *name;
2511 int pref_len, nam_len, parent_times, has_predicate;
Michal Vasko184521f2015-09-24 13:14:26 +02002512 int i, first_iter, rc;
Michal Vasko1f76a282015-08-04 16:16:53 +02002513
Michal Vasko184521f2015-09-24 13:14:26 +02002514 first_iter = 1;
Michal Vasko1f76a282015-08-04 16:16:53 +02002515 parent_times = 0;
2516 id = path;
2517
2518 do {
2519 if ((i = parse_path_arg(id, &prefix, &pref_len, &name, &nam_len, &parent_times, &has_predicate)) < 1) {
Radek Krejciadb57612016-02-16 13:34:34 +01002520 LOGVAL(LYE_INCHAR, line, parent_tpdf ? 0 : LY_VLOG_LYS, parent_tpdf ? NULL : parent, id[-i], &id[-i]);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002521 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02002522 }
2523 id += i;
2524
Michal Vasko184521f2015-09-24 13:14:26 +02002525 if (first_iter) {
Michal Vasko1f76a282015-08-04 16:16:53 +02002526 if (parent_times == -1) {
Radek Krejcic071c542016-01-27 14:57:51 +01002527 /* resolve prefix of the module */
Radek Krejciadb57612016-02-16 13:34:34 +01002528 mod = lys_get_import_module(parent->module, NULL, 0, prefix, pref_len);
Radek Krejcic071c542016-01-27 14:57:51 +01002529 /* get start node */
2530 node = mod ? mod->data : NULL;
Michal Vasko58090902015-08-13 14:04:15 +02002531 if (!node) {
Michal Vasko184521f2015-09-24 13:14:26 +02002532 if (!first) {
Radek Krejciadb57612016-02-16 13:34:34 +01002533 LOGVAL(LYE_NORESOLV, line, parent_tpdf ? 0 : LY_VLOG_LYS, parent_tpdf ? NULL : parent, path);
Michal Vasko184521f2015-09-24 13:14:26 +02002534 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002535 return EXIT_FAILURE;
Michal Vasko58090902015-08-13 14:04:15 +02002536 }
Michal Vasko1f76a282015-08-04 16:16:53 +02002537 } else if (parent_times > 0) {
Michal Vasko73ae2562015-08-06 11:58:13 +02002538 /* node is the parent already, skip one ".." */
Radek Krejci2f12f852016-01-08 12:59:57 +01002539 if (parent_tpdf) {
2540 /* the path is not allowed to contain relative path since we are in top level typedef */
Radek Krejciadb57612016-02-16 13:34:34 +01002541 LOGVAL(LYE_NORESOLV, line, 0, NULL, path);
Radek Krejci2f12f852016-01-08 12:59:57 +01002542 return -1;
2543 }
2544
Radek Krejciadb57612016-02-16 13:34:34 +01002545 node = parent;
Michal Vasko58090902015-08-13 14:04:15 +02002546 i = 0;
2547 while (1) {
Michal Vasko1f76a282015-08-04 16:16:53 +02002548 if (!node) {
Michal Vasko184521f2015-09-24 13:14:26 +02002549 if (!first) {
Radek Krejciadb57612016-02-16 13:34:34 +01002550 LOGVAL(LYE_NORESOLV, line, parent_tpdf ? 0 : LY_VLOG_LYS, parent_tpdf ? NULL : parent, path);
Michal Vasko184521f2015-09-24 13:14:26 +02002551 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002552 return EXIT_FAILURE;
Michal Vasko1f76a282015-08-04 16:16:53 +02002553 }
Michal Vasko58090902015-08-13 14:04:15 +02002554
2555 /* this node is a wrong node, we actually need the augment target */
2556 if (node->nodetype == LYS_AUGMENT) {
2557 node = ((struct lys_node_augment *)node)->target;
2558 if (!node) {
2559 continue;
2560 }
2561 }
2562
2563 ++i;
2564 if (i == parent_times) {
2565 break;
2566 }
2567 node = node->parent;
Michal Vasko1f76a282015-08-04 16:16:53 +02002568 }
Michal Vasko36cbaa42015-12-14 13:15:48 +01002569
Michal Vasko1f76a282015-08-04 16:16:53 +02002570 node = node->child;
Michal Vaskoe01eca52015-08-13 14:42:02 +02002571 } else {
2572 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002573 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02002574 }
Michal Vasko36cbaa42015-12-14 13:15:48 +01002575
Michal Vasko184521f2015-09-24 13:14:26 +02002576 first_iter = 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02002577 } else {
2578 node = node->child;
2579 }
2580
Michal Vasko6c629ac2016-02-15 14:08:23 +01002581 if (!prefix) {
Radek Krejciadb57612016-02-16 13:34:34 +01002582 prefix = lys_node_module(parent)->name;
Michal Vasko6c629ac2016-02-15 14:08:23 +01002583 }
2584
Michal Vasko36cbaa42015-12-14 13:15:48 +01002585 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 +02002586 if (rc) {
Michal Vasko184521f2015-09-24 13:14:26 +02002587 if ((rc == -1) || !first) {
Radek Krejciadb57612016-02-16 13:34:34 +01002588 LOGVAL(LYE_NORESOLV, line, parent_tpdf ? 0 : LY_VLOG_LYS, parent_tpdf ? NULL : parent, path);
Michal Vasko184521f2015-09-24 13:14:26 +02002589 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002590 return rc;
Michal Vasko1f76a282015-08-04 16:16:53 +02002591 }
Michal Vasko1f76a282015-08-04 16:16:53 +02002592
2593 if (has_predicate) {
2594 /* we have predicate, so the current result must be list */
2595 if (node->nodetype != LYS_LIST) {
Radek Krejciadb57612016-02-16 13:34:34 +01002596 LOGVAL(LYE_NORESOLV, line, parent_tpdf ? 0 : LY_VLOG_LYS, parent_tpdf ? NULL : parent, path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002597 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02002598 }
2599
Radek Krejciadb57612016-02-16 13:34:34 +01002600 i = resolve_path_predicate_schema(id, node, parent, first, line);
Michal Vasko184521f2015-09-24 13:14:26 +02002601 if (!i) {
Michal Vaskof9664da2015-08-24 15:03:30 +02002602 return EXIT_FAILURE;
Michal Vasko184521f2015-09-24 13:14:26 +02002603 } else if (i < 0) {
2604 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02002605 }
2606 id += i;
2607 }
2608 } while (id[0]);
2609
Radek Krejcib1c12512015-08-11 11:22:04 +02002610 /* the target must be leaf or leaf-list */
2611 if (!(node->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
Radek Krejciadb57612016-02-16 13:34:34 +01002612 LOGVAL(LYE_NORESOLV, line, parent_tpdf ? 0 : LY_VLOG_LYS, parent_tpdf ? NULL : parent, path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002613 return -1;
Radek Krejcib1c12512015-08-11 11:22:04 +02002614 }
2615
Radek Krejcicf509982015-12-15 09:22:44 +01002616 /* check status */
Radek Krejciadb57612016-02-16 13:34:34 +01002617 if (lyp_check_status(parent->flags, parent->module, parent->name,
2618 node->flags, node->module, node->name, line, node)) {
Radek Krejcicf509982015-12-15 09:22:44 +01002619 return -1;
2620 }
2621
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002622 if (ret) {
2623 *ret = node;
2624 }
2625 return EXIT_SUCCESS;
Michal Vasko1f76a282015-08-04 16:16:53 +02002626}
2627
Michal Vasko730dfdf2015-08-11 14:48:05 +02002628/**
Michal Vaskof39142b2015-10-21 11:40:05 +02002629 * @brief Resolve instance-identifier predicate in JSON data format.
2630 * Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002631 *
Michal Vaskobb211122015-08-19 14:03:11 +02002632 * @param[in] pred Predicate to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002633 * @param[in,out] node_match Nodes matching the restriction without
2634 * the predicate. Nodes not satisfying
2635 * the predicate are removed.
2636 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002637 * @return Number of characters successfully parsed,
2638 * positive on success, negative on failure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002639 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002640static int
Michal Vaskof39142b2015-10-21 11:40:05 +02002641resolve_predicate(const char *pred, struct unres_data *node_match)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002642{
Michal Vasko730dfdf2015-08-11 14:48:05 +02002643 /* ... /node[target = value] ... */
Michal Vasko1f2cc332015-08-19 11:18:32 +02002644 struct unres_data target_match;
2645 struct ly_ctx *ctx;
Michal Vasko1e62a092015-12-01 12:27:20 +01002646 const struct lys_module *mod;
Michal Vasko1f2cc332015-08-19 11:18:32 +02002647 const char *model, *name, *value;
2648 char *str;
2649 int mod_len, nam_len, val_len, i, has_predicate, cur_idx, idx, parsed;
2650 uint32_t j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002651
Michal Vasko1f2cc332015-08-19 11:18:32 +02002652 assert(pred && node_match->count);
2653
Michal Vaskocf024702015-10-08 15:01:42 +02002654 ctx = node_match->node[0]->schema->module->ctx;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002655 idx = -1;
2656 parsed = 0;
2657
2658 do {
Michal Vaskof39142b2015-10-21 11:40:05 +02002659 if ((i = parse_predicate(pred, &model, &mod_len, &name, &nam_len, &value, &val_len, &has_predicate)) < 1) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002660 return -parsed+i;
2661 }
2662 parsed += i;
2663 pred += i;
2664
Michal Vasko1f2cc332015-08-19 11:18:32 +02002665 /* pos */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002666 if (isdigit(name[0])) {
2667 idx = atoi(name);
2668 }
2669
Michal Vasko1f2cc332015-08-19 11:18:32 +02002670 for (cur_idx = 0, j = 0; j < node_match->count; ++cur_idx) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002671 /* target */
Michal Vasko1f2cc332015-08-19 11:18:32 +02002672 memset(&target_match, 0, sizeof target_match);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002673 if ((name[0] == '.') || !value) {
Michal Vasko1f2cc332015-08-19 11:18:32 +02002674 target_match.count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02002675 target_match.node = malloc(sizeof *target_match.node);
Michal Vasko253035f2015-12-17 16:58:13 +01002676 if (!target_match.node) {
2677 LOGMEM;
2678 return -1;
2679 }
Michal Vaskocf024702015-10-08 15:01:42 +02002680 target_match.node[0] = node_match->node[j];
Michal Vasko1f2cc332015-08-19 11:18:32 +02002681 } else {
2682 str = strndup(model, mod_len);
2683 mod = ly_ctx_get_module(ctx, str, NULL);
2684 free(str);
2685
Radek Krejci804836a2016-02-03 10:39:55 +01002686 if (resolve_data(mod, name, nam_len, node_match->node[j]->child, &target_match)) {
Michal Vasko1f2cc332015-08-19 11:18:32 +02002687 goto remove_instid;
2688 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002689 }
2690
2691 /* check that we have the correct type */
2692 if (name[0] == '.') {
Michal Vaskocf024702015-10-08 15:01:42 +02002693 if (node_match->node[j]->schema->nodetype != LYS_LEAFLIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002694 goto remove_instid;
2695 }
2696 } else if (value) {
Michal Vaskocf024702015-10-08 15:01:42 +02002697 if (node_match->node[j]->schema->nodetype != LYS_LIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002698 goto remove_instid;
2699 }
2700 }
2701
Michal Vasko83a6c462015-10-08 16:43:53 +02002702 if ((value && (strncmp(((struct lyd_node_leaf_list *)target_match.node[0])->value_str, value, val_len)
2703 || ((struct lyd_node_leaf_list *)target_match.node[0])->value_str[val_len]))
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002704 || (!value && (idx != cur_idx))) {
2705 goto remove_instid;
2706 }
2707
Michal Vaskocf024702015-10-08 15:01:42 +02002708 free(target_match.node);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002709
2710 /* leafref is ok, continue check with next leafref */
Michal Vasko1f2cc332015-08-19 11:18:32 +02002711 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002712 continue;
2713
2714remove_instid:
Michal Vaskocf024702015-10-08 15:01:42 +02002715 free(target_match.node);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002716
2717 /* does not fulfill conditions, remove leafref record */
Michal Vasko1f2cc332015-08-19 11:18:32 +02002718 unres_data_del(node_match, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002719 }
2720 } while (has_predicate);
2721
2722 return parsed;
2723}
2724
Michal Vasko730dfdf2015-08-11 14:48:05 +02002725/**
Michal Vaskof39142b2015-10-21 11:40:05 +02002726 * @brief Resolve instance-identifier in JSON data format. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002727 *
Radek Krejciadb57612016-02-16 13:34:34 +01002728 * @param[in] data Data node where the path is used
Michal Vasko730dfdf2015-08-11 14:48:05 +02002729 * @param[in] path Instance-identifier node value.
Radek Krejcic5090c32015-08-12 09:46:19 +02002730 * @param[in] line Source line for error messages.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002731 *
Radek Krejcic5090c32015-08-12 09:46:19 +02002732 * @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 +02002733 */
Michal Vasko184521f2015-09-24 13:14:26 +02002734static struct lyd_node *
Michal Vaskof39142b2015-10-21 11:40:05 +02002735resolve_instid(struct lyd_node *data, const char *path, int line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002736{
Radek Krejcic5090c32015-08-12 09:46:19 +02002737 int i = 0, j;
2738 struct lyd_node *result = NULL;
Michal Vasko1e62a092015-12-01 12:27:20 +01002739 const struct lys_module *mod = NULL;
Radek Krejcic5090c32015-08-12 09:46:19 +02002740 struct ly_ctx *ctx = data->schema->module->ctx;
Michal Vasko1f2cc332015-08-19 11:18:32 +02002741 const char *model, *name;
Radek Krejcic5090c32015-08-12 09:46:19 +02002742 char *str;
Michal Vasko1f2cc332015-08-19 11:18:32 +02002743 int mod_len, name_len, has_predicate;
2744 struct unres_data node_match;
2745 uint32_t k;
2746
2747 memset(&node_match, 0, sizeof node_match);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002748
Radek Krejcic5090c32015-08-12 09:46:19 +02002749 /* we need root to resolve absolute path */
2750 for (; data->parent; data = data->parent);
Michal Vaskodb9323c2015-10-16 10:32:44 +02002751 /* we're still parsing it and the pointer is not correct yet */
Michal Vasko0491ab32015-08-19 14:28:29 +02002752 if (data->prev) {
2753 for (; data->prev->next; data = data->prev);
2754 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002755
Radek Krejcic5090c32015-08-12 09:46:19 +02002756 /* search for the instance node */
2757 while (path[i]) {
Michal Vaskof39142b2015-10-21 11:40:05 +02002758 j = parse_instance_identifier(&path[i], &model, &mod_len, &name, &name_len, &has_predicate);
Radek Krejcic5090c32015-08-12 09:46:19 +02002759 if (j <= 0) {
Radek Krejciadb57612016-02-16 13:34:34 +01002760 LOGVAL(LYE_INCHAR, line, LY_VLOG_LYD, data, path[i-j], &path[i-j]);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002761 goto error;
2762 }
Radek Krejcic5090c32015-08-12 09:46:19 +02002763 i += j;
Michal Vaskob387c482015-08-12 09:32:59 +02002764
Michal Vasko1f2cc332015-08-19 11:18:32 +02002765 str = strndup(model, mod_len);
Michal Vasko253035f2015-12-17 16:58:13 +01002766 if (!str) {
2767 LOGMEM;
2768 goto error;
2769 }
Michal Vasko1f2cc332015-08-19 11:18:32 +02002770 mod = ly_ctx_get_module(ctx, str, NULL);
2771 free(str);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002772
Radek Krejcic5090c32015-08-12 09:46:19 +02002773 if (!mod) {
2774 /* no instance exists */
2775 return NULL;
2776 }
2777
Michal Vasko1f2cc332015-08-19 11:18:32 +02002778 if (resolve_data(mod, name, name_len, data, &node_match)) {
Radek Krejcic5090c32015-08-12 09:46:19 +02002779 /* no instance exists */
2780 return NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002781 }
2782
2783 if (has_predicate) {
2784 /* we have predicate, so the current results must be list or leaf-list */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002785 for (k = 0; k < node_match.count;) {
Michal Vaskocf024702015-10-08 15:01:42 +02002786 if ((node_match.node[k]->schema->nodetype == LYS_LIST &&
2787 ((struct lys_node_list *)node_match.node[k]->schema)->keys)
2788 || (node_match.node[k]->schema->nodetype == LYS_LEAFLIST)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002789 /* instid is ok, continue check with next instid */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002790 ++k;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002791 continue;
2792 }
2793
2794 /* does not fulfill conditions, remove inst record */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002795 unres_data_del(&node_match, k);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002796 }
Radek Krejcic5090c32015-08-12 09:46:19 +02002797
Michal Vaskof39142b2015-10-21 11:40:05 +02002798 j = resolve_predicate(&path[i], &node_match);
Radek Krejcic5090c32015-08-12 09:46:19 +02002799 if (j < 1) {
Radek Krejciadb57612016-02-16 13:34:34 +01002800 LOGVAL(LYE_INPRED, line, LY_VLOG_LYD, data, &path[i-j]);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002801 goto error;
2802 }
Michal Vasko1f2cc332015-08-19 11:18:32 +02002803 i += j;
Michal Vaskob387c482015-08-12 09:32:59 +02002804
Michal Vasko1f2cc332015-08-19 11:18:32 +02002805 if (!node_match.count) {
Radek Krejcic5090c32015-08-12 09:46:19 +02002806 /* no instance exists */
2807 return NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002808 }
2809 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002810 }
2811
Michal Vasko1f2cc332015-08-19 11:18:32 +02002812 if (!node_match.count) {
Radek Krejcic5090c32015-08-12 09:46:19 +02002813 /* no instance exists */
2814 return NULL;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002815 } else if (node_match.count > 1) {
Radek Krejcic5090c32015-08-12 09:46:19 +02002816 /* instance identifier must resolve to a single node */
Radek Krejciadb57612016-02-16 13:34:34 +01002817 LOGVAL(LYE_TOOMANY, line, LY_VLOG_LYD, data, path, "data tree");
Radek Krejcic5090c32015-08-12 09:46:19 +02002818
2819 /* cleanup */
Michal Vaskocf024702015-10-08 15:01:42 +02002820 free(node_match.node);
Radek Krejcic5090c32015-08-12 09:46:19 +02002821
2822 return NULL;
2823 } else {
2824 /* we have required result, remember it and cleanup */
Michal Vaskocf024702015-10-08 15:01:42 +02002825 result = node_match.node[0];
2826 free(node_match.node);
Radek Krejcic5090c32015-08-12 09:46:19 +02002827
2828 return result;
2829 }
2830
2831error:
2832
2833 /* cleanup */
Michal Vaskocf024702015-10-08 15:01:42 +02002834 free(node_match.node);
Radek Krejcic5090c32015-08-12 09:46:19 +02002835
2836 return NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002837}
2838
Michal Vasko730dfdf2015-08-11 14:48:05 +02002839/**
2840 * @brief Passes config flag down to children. Does not log.
2841 *
2842 * @param[in] node Parent node.
2843 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002844static void
Radek Krejci1d82ef62015-08-07 14:44:40 +02002845inherit_config_flag(struct lys_node *node)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002846{
Radek Krejci1d82ef62015-08-07 14:44:40 +02002847 LY_TREE_FOR(node, node) {
2848 node->flags |= node->parent->flags & LYS_CONFIG_MASK;
2849 inherit_config_flag(node->child);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002850 }
2851}
2852
Michal Vasko730dfdf2015-08-11 14:48:05 +02002853/**
Michal Vasko7178e692016-02-12 15:58:05 +01002854 * @brief Resolve augment target. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002855 *
Michal Vaskobb211122015-08-19 14:03:11 +02002856 * @param[in] aug Augment to use.
Michal Vasko3edeaf72016-02-11 13:17:43 +01002857 * @param[in] siblings Nodes where to start the search in. If set, uses augment, if not, standalone augment.
Michal Vasko7178e692016-02-12 15:58:05 +01002858 * @param[in] first Whether this is the first resolution try.
2859 * @param[in] line Line in the input file.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002860 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002861 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002862 */
Michal Vasko7178e692016-02-12 15:58:05 +01002863static int
2864resolve_augment(struct lys_node_augment *aug, struct lys_node *siblings, int first, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002865{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002866 int rc;
Michal Vasko1d87a922015-08-21 12:57:16 +02002867 struct lys_node *sub;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002868
Michal Vasko1d87a922015-08-21 12:57:16 +02002869 assert(aug);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002870
2871 /* resolve target node */
Michal Vasko3edeaf72016-02-11 13:17:43 +01002872 rc = resolve_augment_schema_nodeid(aug->target_name, siblings, (siblings ? NULL : aug->module), (const struct lys_node **)&aug->target);
Michal Vasko7178e692016-02-12 15:58:05 +01002873 if (rc == -1) {
2874 return -1;
2875 }
2876 if (rc > 0) {
Radek Krejciadb57612016-02-16 13:34:34 +01002877 LOGVAL(LYE_INCHAR, line, LY_VLOG_LYS, aug, aug->target_name[rc - 1], &aug->target_name[rc - 1]);
Michal Vasko3edeaf72016-02-11 13:17:43 +01002878 return -1;
2879 }
2880 if (!aug->target) {
Michal Vasko7178e692016-02-12 15:58:05 +01002881 if (!first) {
Radek Krejciadb57612016-02-16 13:34:34 +01002882 LOGVAL(LYE_INRESOLV, line, LY_VLOG_LYS, aug, "augment", aug->target_name);
Michal Vasko7178e692016-02-12 15:58:05 +01002883 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01002884 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002885 }
2886
2887 if (!aug->child) {
2888 /* nothing to do */
Michal Vasko1d87a922015-08-21 12:57:16 +02002889 LOGWRN("Augment \"%s\" without children.", aug->target_name);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002890 return EXIT_SUCCESS;
2891 }
2892
2893 /* inherit config information from parent, augment does not have
2894 * config property, but we need to keep the information for subelements
2895 */
Radek Krejci1574a8d2015-08-03 14:16:52 +02002896 aug->flags |= aug->target->flags & LYS_CONFIG_MASK;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002897 LY_TREE_FOR(aug->child, sub) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002898 inherit_config_flag(sub);
2899 }
2900
Radek Krejcic071c542016-01-27 14:57:51 +01002901 /* check identifier uniqueness as in lys_node_addchild() */
Michal Vasko1d87a922015-08-21 12:57:16 +02002902 LY_TREE_FOR(aug->child, sub) {
Michal Vasko6c629ac2016-02-15 14:08:23 +01002903 if (lys_check_id(sub, aug->parent, lys_module(aug->module))) {
Michal Vasko3e6665f2015-08-17 14:00:38 +02002904 return -1;
Radek Krejci07911992015-08-14 15:13:31 +02002905 }
2906 }
Radek Krejci0acbe1b2015-08-04 09:33:49 +02002907 /* reconnect augmenting data into the target - add them to the target child list */
2908 if (aug->target->child) {
Michal Vasko1d87a922015-08-21 12:57:16 +02002909 sub = aug->target->child->prev; /* remember current target's last node */
2910 sub->next = aug->child; /* connect augmenting data after target's last node */
Radek Krejci0acbe1b2015-08-04 09:33:49 +02002911 aug->target->child->prev = aug->child->prev; /* new target's last node is last augmenting node */
Michal Vasko1d87a922015-08-21 12:57:16 +02002912 aug->child->prev = sub; /* finish connecting of both child lists */
Radek Krejci0acbe1b2015-08-04 09:33:49 +02002913 } else {
2914 aug->target->child = aug->child;
2915 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002916
2917 return EXIT_SUCCESS;
2918}
2919
Michal Vasko730dfdf2015-08-11 14:48:05 +02002920/**
2921 * @brief Resolve uses, apply augments, refines. Logs directly.
2922 *
Michal Vaskobb211122015-08-19 14:03:11 +02002923 * @param[in] uses Uses to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002924 * @param[in,out] unres List of unresolved items.
2925 * @param[in] line Line in the input file.
2926 *
Michal Vaskodef0db12015-10-07 13:22:48 +02002927 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002928 */
Michal Vasko184521f2015-09-24 13:14:26 +02002929static int
Michal Vaskodef0db12015-10-07 13:22:48 +02002930resolve_uses(struct lys_node_uses *uses, struct unres_schema *unres, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002931{
2932 struct ly_ctx *ctx;
Michal Vasko1e62a092015-12-01 12:27:20 +01002933 struct lys_node *node = NULL;
2934 const struct lys_node *node_aux;
Radek Krejci76512572015-08-04 09:47:08 +02002935 struct lys_refine *rfn;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02002936 struct lys_restr *must, **old_must;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002937 int i, j, rc;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02002938 uint8_t size, *old_size;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002939
Michal Vasko71e1aa82015-08-12 12:17:51 +02002940 assert(uses->grp);
Michal Vaskodef0db12015-10-07 13:22:48 +02002941 /* HACK just check that the grouing is resolved */
2942 assert(!uses->grp->nacm);
Michal Vasko71e1aa82015-08-12 12:17:51 +02002943
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002944 /* copy the data nodes from grouping into the uses context */
Michal Vasko1e62a092015-12-01 12:27:20 +01002945 LY_TREE_FOR(uses->grp->child, node_aux) {
Michal Vaskod51d6ad2016-02-16 13:24:31 +01002946 node = lys_node_dup(uses->module, (struct lys_node *)uses, node_aux, uses->flags, uses->nacm, unres, 0);
Michal Vasko1e62a092015-12-01 12:27:20 +01002947 if (!node) {
Radek Krejciadb57612016-02-16 13:34:34 +01002948 LOGVAL(LYE_SPEC, line, LY_VLOG_LYS, uses, "Copying data from grouping failed.");
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002949 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002950 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002951 }
2952 ctx = uses->module->ctx;
2953
Michal Vaskodef0db12015-10-07 13:22:48 +02002954 /* we managed to copy the grouping, the rest must be possible to resolve */
2955
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002956 /* apply refines */
2957 for (i = 0; i < uses->refine_size; i++) {
2958 rfn = &uses->refine[i];
Michal Vasko3edeaf72016-02-11 13:17:43 +01002959 rc = resolve_descendant_schema_nodeid(rfn->target_name, uses->child, LYS_NO_RPC_NOTIF_NODE,
2960 (const struct lys_node **)&node);
Michal Vasko9bb061b2016-02-12 11:00:19 +01002961 if (rc || !node) {
Radek Krejciadb57612016-02-16 13:34:34 +01002962 LOGVAL(LYE_INARG, line, LY_VLOG_LYS, uses, rfn->target_name, "refine");
Michal Vaskodef0db12015-10-07 13:22:48 +02002963 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002964 }
2965
Radek Krejci1d82ef62015-08-07 14:44:40 +02002966 if (rfn->target_type && !(node->nodetype & rfn->target_type)) {
Radek Krejciadb57612016-02-16 13:34:34 +01002967 LOGVAL(LYE_SPEC, line, LY_VLOG_LYS, uses, "Refine substatements not applicable to the target-node.");
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002968 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002969 }
2970
2971 /* description on any nodetype */
2972 if (rfn->dsc) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002973 lydict_remove(ctx, node->dsc);
2974 node->dsc = lydict_insert(ctx, rfn->dsc, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002975 }
2976
2977 /* reference on any nodetype */
2978 if (rfn->ref) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002979 lydict_remove(ctx, node->ref);
2980 node->ref = lydict_insert(ctx, rfn->ref, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002981 }
2982
2983 /* config on any nodetype */
Radek Krejci1574a8d2015-08-03 14:16:52 +02002984 if (rfn->flags & LYS_CONFIG_MASK) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002985 node->flags &= ~LYS_CONFIG_MASK;
2986 node->flags |= (rfn->flags & LYS_CONFIG_MASK);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002987 }
2988
2989 /* default value ... */
2990 if (rfn->mod.dflt) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02002991 if (node->nodetype == LYS_LEAF) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002992 /* leaf */
Radek Krejci1d82ef62015-08-07 14:44:40 +02002993 lydict_remove(ctx, ((struct lys_node_leaf *)node)->dflt);
2994 ((struct lys_node_leaf *)node)->dflt = lydict_insert(ctx, rfn->mod.dflt, 0);
2995 } else if (node->nodetype == LYS_CHOICE) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002996 /* choice */
Michal Vasko3edeaf72016-02-11 13:17:43 +01002997 rc = resolve_choice_default_schema_nodeid(rfn->mod.dflt, node->child,
2998 (const struct lys_node **)&((struct lys_node_choice *)node)->dflt);
Michal Vasko9bb061b2016-02-12 11:00:19 +01002999 if (rc || !((struct lys_node_choice *)node)->dflt) {
Radek Krejciadb57612016-02-16 13:34:34 +01003000 LOGVAL(LYE_INARG, line, LY_VLOG_LYS, uses, rfn->mod.dflt, "default");
Michal Vaskodef0db12015-10-07 13:22:48 +02003001 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003002 }
3003 }
3004 }
3005
3006 /* mandatory on leaf, anyxml or choice */
Radek Krejci1574a8d2015-08-03 14:16:52 +02003007 if (rfn->flags & LYS_MAND_MASK) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02003008 if (node->nodetype & (LYS_LEAF | LYS_ANYXML | LYS_CHOICE)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003009 /* remove current value */
Radek Krejci1d82ef62015-08-07 14:44:40 +02003010 node->flags &= ~LYS_MAND_MASK;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003011
3012 /* set new value */
Radek Krejci1d82ef62015-08-07 14:44:40 +02003013 node->flags |= (rfn->flags & LYS_MAND_MASK);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003014 }
3015 }
3016
3017 /* presence on container */
Radek Krejci1d82ef62015-08-07 14:44:40 +02003018 if ((node->nodetype & LYS_CONTAINER) && rfn->mod.presence) {
3019 lydict_remove(ctx, ((struct lys_node_container *)node)->presence);
3020 ((struct lys_node_container *)node)->presence = lydict_insert(ctx, rfn->mod.presence, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003021 }
3022
3023 /* min/max-elements on list or leaf-list */
3024 /* magic - bit 3 in flags means min set, bit 4 says max set */
Radek Krejci1d82ef62015-08-07 14:44:40 +02003025 if (node->nodetype == LYS_LIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003026 if (rfn->flags & 0x04) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02003027 ((struct lys_node_list *)node)->min = rfn->mod.list.min;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003028 }
3029 if (rfn->flags & 0x08) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02003030 ((struct lys_node_list *)node)->max = rfn->mod.list.max;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003031 }
Radek Krejci1d82ef62015-08-07 14:44:40 +02003032 } else if (node->nodetype == LYS_LEAFLIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003033 if (rfn->flags & 0x04) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02003034 ((struct lys_node_leaflist *)node)->min = rfn->mod.list.min;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003035 }
3036 if (rfn->flags & 0x08) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02003037 ((struct lys_node_leaflist *)node)->max = rfn->mod.list.max;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003038 }
3039 }
3040
3041 /* must in leaf, leaf-list, list, container or anyxml */
3042 if (rfn->must_size) {
Michal Vaskoef2fdc82015-09-24 09:54:42 +02003043 switch (node->nodetype) {
3044 case LYS_LEAF:
3045 old_size = &((struct lys_node_leaf *)node)->must_size;
3046 old_must = &((struct lys_node_leaf *)node)->must;
3047 break;
3048 case LYS_LEAFLIST:
3049 old_size = &((struct lys_node_leaflist *)node)->must_size;
3050 old_must = &((struct lys_node_leaflist *)node)->must;
3051 break;
3052 case LYS_LIST:
3053 old_size = &((struct lys_node_list *)node)->must_size;
3054 old_must = &((struct lys_node_list *)node)->must;
3055 break;
3056 case LYS_CONTAINER:
3057 old_size = &((struct lys_node_container *)node)->must_size;
3058 old_must = &((struct lys_node_container *)node)->must;
3059 break;
3060 case LYS_ANYXML:
3061 old_size = &((struct lys_node_anyxml *)node)->must_size;
3062 old_must = &((struct lys_node_anyxml *)node)->must;
3063 break;
3064 default:
3065 LOGINT;
Radek Krejcie4e4d722015-10-05 16:53:50 +02003066 return -1;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02003067 }
3068
3069 size = *old_size + rfn->must_size;
3070 must = realloc(*old_must, size * sizeof *rfn->must);
3071 if (!must) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003072 LOGMEM;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003073 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003074 }
Michal Vaskoef2fdc82015-09-24 09:54:42 +02003075 for (i = 0, j = *old_size; i < rfn->must_size; i++, j++) {
3076 must[j].expr = lydict_insert(ctx, rfn->must[i].expr, 0);
3077 must[j].dsc = lydict_insert(ctx, rfn->must[i].dsc, 0);
3078 must[j].ref = lydict_insert(ctx, rfn->must[i].ref, 0);
3079 must[j].eapptag = lydict_insert(ctx, rfn->must[i].eapptag, 0);
3080 must[j].emsg = lydict_insert(ctx, rfn->must[i].emsg, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003081 }
3082
Michal Vaskoef2fdc82015-09-24 09:54:42 +02003083 *old_must = must;
3084 *old_size = size;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003085 }
3086 }
3087
3088 /* apply augments */
3089 for (i = 0; i < uses->augment_size; i++) {
Michal Vasko7178e692016-02-12 15:58:05 +01003090 rc = resolve_augment(&uses->augment[i], uses->child, 0, line);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003091 if (rc) {
Michal Vaskodef0db12015-10-07 13:22:48 +02003092 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003093 }
3094 }
3095
3096 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003097}
3098
Michal Vasko730dfdf2015-08-11 14:48:05 +02003099/**
3100 * @brief Resolve base identity recursively. Does not log.
3101 *
3102 * @param[in] module Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02003103 * @param[in] ident Identity to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003104 * @param[in] basename Base name of the identity.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003105 * @param[out] ret Pointer to the resolved identity. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003106 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003107 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003108 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003109static int
Michal Vasko1e62a092015-12-01 12:27:20 +01003110resolve_base_ident_sub(const struct lys_module *module, struct lys_ident *ident, const char *basename,
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003111 struct lys_ident **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003112{
Michal Vaskof02e3742015-08-05 16:27:02 +02003113 uint32_t i, j;
Radek Krejcia52656e2015-08-05 13:41:50 +02003114 struct lys_ident *base_iter = NULL;
3115 struct lys_ident_der *der;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003116
Radek Krejcicf509982015-12-15 09:22:44 +01003117 assert(ret);
3118
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003119 /* search module */
3120 for (i = 0; i < module->ident_size; i++) {
3121 if (!strcmp(basename, module->ident[i].name)) {
3122
3123 if (!ident) {
3124 /* just search for type, so do not modify anything, just return
3125 * the base identity pointer
3126 */
Radek Krejcicf509982015-12-15 09:22:44 +01003127 *ret = &module->ident[i];
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003128 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003129 }
3130
3131 /* we are resolving identity definition, so now update structures */
3132 ident->base = base_iter = &module->ident[i];
3133
3134 break;
3135 }
3136 }
3137
3138 /* search submodules */
3139 if (!base_iter) {
Radek Krejcic071c542016-01-27 14:57:51 +01003140 for (j = 0; j < module->inc_size && module->inc[j].submodule; j++) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003141 for (i = 0; i < module->inc[j].submodule->ident_size; i++) {
3142 if (!strcmp(basename, module->inc[j].submodule->ident[i].name)) {
3143
3144 if (!ident) {
Radek Krejcicf509982015-12-15 09:22:44 +01003145 *ret = &module->inc[j].submodule->ident[i];
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003146 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003147 }
3148
3149 ident->base = base_iter = &module->inc[j].submodule->ident[i];
3150 break;
3151 }
3152 }
3153 }
3154 }
3155
3156 /* we found it somewhere */
3157 if (base_iter) {
3158 while (base_iter) {
3159 for (der = base_iter->der; der && der->next; der = der->next);
3160 if (der) {
3161 der->next = malloc(sizeof *der);
3162 der = der->next;
3163 } else {
3164 ident->base->der = der = malloc(sizeof *der);
3165 }
Michal Vasko253035f2015-12-17 16:58:13 +01003166 if (!der) {
3167 LOGMEM;
3168 return EXIT_FAILURE;
3169 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003170 der->next = NULL;
3171 der->ident = ident;
3172
3173 base_iter = base_iter->base;
3174 }
Radek Krejcicf509982015-12-15 09:22:44 +01003175 *ret = ident->base;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003176 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003177 }
3178
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003179 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003180}
3181
Michal Vasko730dfdf2015-08-11 14:48:05 +02003182/**
3183 * @brief Resolve base identity. Logs directly.
3184 *
3185 * @param[in] module Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02003186 * @param[in] ident Identity to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003187 * @param[in] basename Base name of the identity.
3188 * @param[in] parent Either "type" or "ident".
Michal Vasko184521f2015-09-24 13:14:26 +02003189 * @param[in] first Whether this is the first resolution try. Affects logging.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003190 * @param[in] line Line in the input file.
Radek Krejcicf509982015-12-15 09:22:44 +01003191 * @param[in,out] type Type structure where we want to resolve identity. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003192 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003193 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003194 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003195static int
Michal Vasko1e62a092015-12-01 12:27:20 +01003196resolve_base_ident(const struct lys_module *module, struct lys_ident *ident, const char *basename, const char* parent,
Radek Krejcicf509982015-12-15 09:22:44 +01003197 int first, uint32_t line, struct lys_type *type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003198{
3199 const char *name;
Michal Vasko2d851a92015-10-20 16:16:36 +02003200 int i, mod_name_len = 0;
Radek Krejcicf509982015-12-15 09:22:44 +01003201 struct lys_ident *target, **ret;
3202 uint8_t flags;
3203 struct lys_module *mod;
3204
3205 assert((ident && !type) || (!ident && type));
3206
3207 if (!type) {
3208 /* have ident to resolve */
3209 ret = &target;
3210 flags = ident->flags;
3211 mod = ident->module;
3212 } else {
3213 /* have type to fill */
3214 ret = &type->info.ident.ref;
3215 flags = type->parent->flags;
3216 mod = type->parent->module;
3217 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003218
3219 /* search for the base identity */
3220 name = strchr(basename, ':');
3221 if (name) {
3222 /* set name to correct position after colon */
Michal Vasko2d851a92015-10-20 16:16:36 +02003223 mod_name_len = name - basename;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003224 name++;
3225
Michal Vasko2d851a92015-10-20 16:16:36 +02003226 if (!strncmp(basename, module->name, mod_name_len) && !module->name[mod_name_len]) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003227 /* prefix refers to the current module, ignore it */
Michal Vasko2d851a92015-10-20 16:16:36 +02003228 mod_name_len = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003229 }
3230 } else {
3231 name = basename;
3232 }
3233
Radek Krejcic071c542016-01-27 14:57:51 +01003234 /* get module where to search */
3235 module = lys_get_import_module(module, NULL, 0, mod_name_len ? basename : NULL, mod_name_len);
3236 if (!module) {
3237 /* identity refers unknown data model */
Radek Krejciadb57612016-02-16 13:34:34 +01003238 LOGVAL(LYE_INMOD, line, 0, NULL, basename);
Radek Krejcic071c542016-01-27 14:57:51 +01003239 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003240 }
3241
Radek Krejcic071c542016-01-27 14:57:51 +01003242 /* search in the identified module ... */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003243 if (!resolve_base_ident_sub(module, ident, name, ret)) {
Radek Krejcicf509982015-12-15 09:22:44 +01003244 goto success;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003245 }
Radek Krejcic071c542016-01-27 14:57:51 +01003246 /* and all its submodules */
3247 for (i = 0; i < module->inc_size && module->inc[i].submodule; i++) {
3248 if (!resolve_base_ident_sub((struct lys_module *)module->inc[i].submodule, ident, name, ret)) {
3249 goto success;
3250 }
3251 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003252
Michal Vasko184521f2015-09-24 13:14:26 +02003253 if (!first) {
Radek Krejciadb57612016-02-16 13:34:34 +01003254 LOGVAL(LYE_INARG, line, 0, NULL, basename, parent);
Michal Vasko184521f2015-09-24 13:14:26 +02003255 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003256 return EXIT_FAILURE;
Radek Krejcicf509982015-12-15 09:22:44 +01003257
3258success:
3259 /* check status */
Radek Krejciadb57612016-02-16 13:34:34 +01003260 if (lyp_check_status(flags, mod, ident ? ident->name : "of type", (*ret)->flags, (*ret)->module, (*ret)->name,
3261 line, NULL)) {
Radek Krejcicf509982015-12-15 09:22:44 +01003262 return -1;
3263 }
3264
3265 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003266}
3267
Michal Vasko730dfdf2015-08-11 14:48:05 +02003268/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003269 * @brief Resolve JSON data format identityref. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003270 *
3271 * @param[in] base Base identity.
Michal Vaskofb0873c2015-08-21 09:00:07 +02003272 * @param[in] ident_name Identityref name.
3273 * @param[in] line Line from the input file.
Radek Krejciadb57612016-02-16 13:34:34 +01003274 * @param[in] node Node where the identityref is being resolved
Michal Vasko730dfdf2015-08-11 14:48:05 +02003275 *
3276 * @return Pointer to the identity resolvent, NULL on error.
3277 */
Radek Krejcia52656e2015-08-05 13:41:50 +02003278struct lys_ident *
Radek Krejciadb57612016-02-16 13:34:34 +01003279resolve_identref(struct lys_ident *base, const char *ident_name, uint32_t line, struct lyd_node *node)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003280{
Michal Vaskoc633ca02015-08-21 14:03:51 +02003281 const char *mod_name, *name;
3282 int mod_name_len, rc;
Radek Krejcia52656e2015-08-05 13:41:50 +02003283 struct lys_ident_der *der;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003284
Michal Vaskofb0873c2015-08-21 09:00:07 +02003285 if (!base || !ident_name) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003286 return NULL;
3287 }
3288
Michal Vaskoc633ca02015-08-21 14:03:51 +02003289 rc = parse_node_identifier(ident_name, &mod_name, &mod_name_len, &name, NULL);
Michal Vaskofb0873c2015-08-21 09:00:07 +02003290 if (rc < (signed)strlen(ident_name)) {
Radek Krejciadb57612016-02-16 13:34:34 +01003291 LOGVAL(LYE_INCHAR, line, LY_VLOG_LYD, node, ident_name[-rc], &ident_name[-rc]);
Michal Vaskofb0873c2015-08-21 09:00:07 +02003292 return NULL;
3293 }
3294
Michal Vaskoc633ca02015-08-21 14:03:51 +02003295 if (!strcmp(base->name, name) && (!mod_name
3296 || (!strncmp(base->module->name, mod_name, mod_name_len) && !base->module->name[mod_name_len]))) {
Michal Vaskofb0873c2015-08-21 09:00:07 +02003297 return base;
3298 }
3299
3300 for (der = base->der; der; der = der->next) {
Michal Vaskoc633ca02015-08-21 14:03:51 +02003301 if (!strcmp(der->ident->name, name) && (!mod_name
3302 || (!strncmp(der->ident->module->name, mod_name, mod_name_len)
3303 && !der->ident->module->name[mod_name_len]))) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003304 /* we have match */
3305 return der->ident;
3306 }
3307 }
3308
Radek Krejciadb57612016-02-16 13:34:34 +01003309 LOGVAL(LYE_INRESOLV, line, LY_VLOG_LYD, node, "identityref", ident_name);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003310 return NULL;
3311}
3312
Michal Vasko730dfdf2015-08-11 14:48:05 +02003313/**
Michal Vasko7955b362015-09-04 14:18:15 +02003314 * @brief Resolve (find) choice default case. Does not log.
3315 *
3316 * @param[in] choic Choice to use.
3317 * @param[in] dflt Name of the default case.
3318 *
3319 * @return Pointer to the default node or NULL.
3320 */
3321static struct lys_node *
3322resolve_choice_dflt(struct lys_node_choice *choic, const char *dflt)
3323{
3324 struct lys_node *child, *ret;
3325
3326 LY_TREE_FOR(choic->child, child) {
3327 if (child->nodetype == LYS_USES) {
3328 ret = resolve_choice_dflt((struct lys_node_choice *)child, dflt);
3329 if (ret) {
3330 return ret;
3331 }
3332 }
3333
3334 if ((child->name == dflt) && (child->nodetype & (LYS_ANYXML | LYS_CASE
3335 | LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST))) {
3336 return child;
3337 }
3338 }
3339
3340 return NULL;
3341}
3342
3343/**
Michal Vaskobb211122015-08-19 14:03:11 +02003344 * @brief Resolve unresolved uses. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003345 *
Michal Vaskobb211122015-08-19 14:03:11 +02003346 * @param[in] uses Uses to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003347 * @param[in] unres Specific unres item.
Michal Vasko407f1bb2015-09-23 15:51:07 +02003348 * @param[in] first Whether this is the first resolution try.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003349 * @param[in] line Line in the input file.
3350 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003351 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003352 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003353static int
Michal Vasko407f1bb2015-09-23 15:51:07 +02003354resolve_unres_schema_uses(struct lys_node_uses *uses, struct unres_schema *unres, int first, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003355{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003356 int rc;
Michal Vaskoe91afce2015-08-12 12:21:00 +02003357 struct lys_node *parent;
3358
3359 /* HACK change unres uses count if it's in a grouping (nacm field used for it) */
3360 for (parent = uses->parent; parent && (parent->nodetype != LYS_GROUPING); parent = parent->parent);
3361
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003362 if (!uses->grp) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01003363 rc = resolve_uses_schema_nodeid(uses->name, (const struct lys_node *)uses, (const struct lys_node_grp **)&uses->grp);
3364 if (rc == -1) {
Radek Krejciadb57612016-02-16 13:34:34 +01003365 LOGVAL(LYE_INRESOLV, line, LY_VLOG_LYS, uses, "grouping", uses->name);
Michal Vasko3edeaf72016-02-11 13:17:43 +01003366 return -1;
3367 } else if (rc > 0) {
Radek Krejciadb57612016-02-16 13:34:34 +01003368 LOGVAL(LYE_INCHAR, line, LY_VLOG_LYS, uses, uses->name[rc - 1], &uses->name[rc - 1]);
Michal Vasko3edeaf72016-02-11 13:17:43 +01003369 return -1;
3370 } else if (!uses->grp) {
3371 if (parent && first) {
Michal Vasko407f1bb2015-09-23 15:51:07 +02003372 ++parent->nacm;
3373 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01003374 return EXIT_FAILURE;
Michal Vasko12e30842015-08-04 11:54:00 +02003375 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003376 }
3377
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003378 if (uses->grp->nacm) {
Michal Vasko407f1bb2015-09-23 15:51:07 +02003379 if (parent && first) {
3380 ++parent->nacm;
3381 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003382 return EXIT_FAILURE;
3383 }
3384
Michal Vaskodef0db12015-10-07 13:22:48 +02003385 rc = resolve_uses(uses, unres, line);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003386 if (!rc) {
3387 /* decrease unres count only if not first try */
Michal Vasko407f1bb2015-09-23 15:51:07 +02003388 if (parent && !first) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003389 if (!parent->nacm) {
3390 LOGINT;
3391 return -1;
3392 }
3393 --parent->nacm;
3394 }
Radek Krejcicf509982015-12-15 09:22:44 +01003395
3396 /* check status */
Radek Krejcic6556022016-01-27 15:16:45 +01003397 if (lyp_check_status(uses->flags, uses->module, "of uses",
Radek Krejciadb57612016-02-16 13:34:34 +01003398 uses->grp->flags, uses->grp->module, uses->grp->name,
3399 line, (struct lys_node *)uses)) {
Radek Krejcicf509982015-12-15 09:22:44 +01003400 return -1;
3401 }
3402
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003403 return EXIT_SUCCESS;
3404 }
3405
Michal Vasko407f1bb2015-09-23 15:51:07 +02003406 if (parent && first && (rc == EXIT_FAILURE)) {
Michal Vaskoe91afce2015-08-12 12:21:00 +02003407 ++parent->nacm;
3408 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003409 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003410}
3411
Michal Vasko730dfdf2015-08-11 14:48:05 +02003412/**
Michal Vasko9957e592015-08-17 15:04:09 +02003413 * @brief Resolve list keys. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003414 *
Michal Vaskobb211122015-08-19 14:03:11 +02003415 * @param[in] list List to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003416 * @param[in] keys_str Keys node value.
Michal Vasko184521f2015-09-24 13:14:26 +02003417 * @param[in] first Whether this is the first resolution try. Affects logging.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003418 * @param[in] line Line in the input file.
3419 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003420 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003421 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003422static int
Michal Vasko36cbaa42015-12-14 13:15:48 +01003423resolve_list_keys(struct lys_node_list *list, const char *keys_str, int first, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003424{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003425 int i, len, rc;
Michal Vasko6c629ac2016-02-15 14:08:23 +01003426 const char *value;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003427
3428 for (i = 0; i < list->keys_size; ++i) {
3429 /* get the key name */
3430 if ((value = strpbrk(keys_str, " \t\n"))) {
3431 len = value - keys_str;
3432 while (isspace(value[0])) {
3433 value++;
3434 }
3435 } else {
3436 len = strlen(keys_str);
3437 }
3438
Michal Vasko6c629ac2016-02-15 14:08:23 +01003439 rc = lys_get_sibling(list->child, lys_module(list->module)->name, 0, keys_str, len, LYS_LEAF, (const struct lys_node **)&list->keys[i]);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003440 if (rc) {
Michal Vasko184521f2015-09-24 13:14:26 +02003441 if ((rc == -1) || !first) {
Radek Krejciadb57612016-02-16 13:34:34 +01003442 LOGVAL(LYE_INRESOLV, line, LY_VLOG_LYS, list, "list keys", keys_str);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003443 }
3444 return rc;
3445 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003446
Radek Krejciadb57612016-02-16 13:34:34 +01003447 if (check_key(list, i, keys_str, len, line)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003448 /* check_key logs */
3449 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003450 }
3451
Radek Krejcicf509982015-12-15 09:22:44 +01003452 /* check status */
Radek Krejcic6556022016-01-27 15:16:45 +01003453 if (lyp_check_status(list->flags, list->module, list->name,
Radek Krejciadb57612016-02-16 13:34:34 +01003454 list->keys[i]->flags, list->keys[i]->module, list->keys[i]->name,
3455 line, (struct lys_node *)list->keys[i])) {
Radek Krejcicf509982015-12-15 09:22:44 +01003456 return -1;
3457 }
3458
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003459 /* prepare for next iteration */
3460 while (value && isspace(value[0])) {
3461 value++;
3462 }
3463 keys_str = value;
3464 }
3465
Michal Vaskof02e3742015-08-05 16:27:02 +02003466 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003467}
3468
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003469/**
Michal Vaskobf19d252015-10-08 15:39:17 +02003470 * @brief Resolve (check) all must conditions of \p node.
3471 * Logs directly.
3472 *
3473 * @param[in] node Data node with optional must statements.
3474 * @param[in] first Whether this is the first resolution to try.
3475 * @param[in] line Line in the input file.
3476 *
3477 * @return EXIT_SUCCESS on pass, EXIT_FAILURE on fail, -1 on error.
3478 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003479static int
Michal Vaskobf19d252015-10-08 15:39:17 +02003480resolve_must(struct lyd_node *node, int first, uint32_t line)
Michal Vaskof02e3742015-08-05 16:27:02 +02003481{
Michal Vaskobf19d252015-10-08 15:39:17 +02003482 uint8_t i, must_size;
3483 struct lys_restr *must;
3484 struct lyxp_set set;
3485
3486 assert(node);
3487 memset(&set, 0, sizeof set);
3488
3489 switch (node->schema->nodetype) {
3490 case LYS_CONTAINER:
3491 must_size = ((struct lys_node_container *)node->schema)->must_size;
3492 must = ((struct lys_node_container *)node->schema)->must;
3493 break;
3494 case LYS_LEAF:
3495 must_size = ((struct lys_node_leaf *)node->schema)->must_size;
3496 must = ((struct lys_node_leaf *)node->schema)->must;
3497 break;
3498 case LYS_LEAFLIST:
3499 must_size = ((struct lys_node_leaflist *)node->schema)->must_size;
3500 must = ((struct lys_node_leaflist *)node->schema)->must;
3501 break;
3502 case LYS_LIST:
3503 must_size = ((struct lys_node_list *)node->schema)->must_size;
3504 must = ((struct lys_node_list *)node->schema)->must;
3505 break;
3506 case LYS_ANYXML:
3507 must_size = ((struct lys_node_anyxml *)node->schema)->must_size;
3508 must = ((struct lys_node_anyxml *)node->schema)->must;
3509 break;
3510 default:
3511 must_size = 0;
3512 break;
3513 }
3514
3515 for (i = 0; i < must_size; ++i) {
Michal Vaskoe1fe43d2015-10-29 11:09:59 +01003516 if (lyxp_eval(must[i].expr, node, &set, 1, line)) {
Michal Vaskobf19d252015-10-08 15:39:17 +02003517 return -1;
3518 }
3519
Michal Vaskoe1fe43d2015-10-29 11:09:59 +01003520 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, node, 1);
Michal Vaskobf19d252015-10-08 15:39:17 +02003521
3522 if (!set.value.bool) {
3523 if (!first) {
Michal Vasko7d3ec592016-02-17 12:06:44 +01003524 LOGVAL(LYE_NOCOND, line, LY_VLOG_LYD, node, "Must", must[i].expr);
Michal Vaskobf19d252015-10-08 15:39:17 +02003525 }
3526 return 1;
3527 }
3528 }
3529
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003530 return EXIT_SUCCESS;
Michal Vaskof02e3742015-08-05 16:27:02 +02003531}
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003532
Michal Vaskobf19d252015-10-08 15:39:17 +02003533/**
Michal Vaskocf024702015-10-08 15:01:42 +02003534 * @brief Resolve (find) when condition context node. Does not log.
3535 *
3536 * @param[in] node Data node, whose conditional definition is being decided.
3537 * @param[in] schema Schema node with a when condition.
3538 *
3539 * @return Context node.
3540 */
3541static struct lyd_node *
3542resolve_when_ctx_node(struct lyd_node *node, struct lys_node *schema)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003543{
Michal Vaskocf024702015-10-08 15:01:42 +02003544 struct lyd_node *parent;
3545 struct lys_node *sparent;
3546 uint16_t i, data_depth, schema_depth;
3547
3548 /* find a not schema-only node */
3549 while (schema->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE | LYS_AUGMENT | LYS_INPUT | LYS_OUTPUT)) {
3550 schema = lys_parent(schema);
3551 if (!schema) {
3552 return NULL;
3553 }
3554 }
3555
3556 /* get node depths */
3557 for (parent = node, data_depth = 0; parent; parent = parent->parent, ++data_depth);
3558 for (sparent = lys_parent(schema), schema_depth = 1; sparent; sparent = lys_parent(sparent)) {
3559 if (sparent->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_ANYXML | LYS_NOTIF | LYS_RPC)) {
3560 ++schema_depth;
3561 }
3562 }
3563 if (data_depth < schema_depth) {
3564 return NULL;
3565 }
3566
3567 /* find the corresponding data node */
3568 for (i = 0; i < data_depth - schema_depth; ++i) {
3569 node = node->parent;
3570 }
3571 if (node->schema != schema) {
3572 return NULL;
3573 }
3574
3575 return node;
3576}
3577
3578/**
3579 * @brief Resolve (check) all when conditions relevant for \p node.
3580 * Logs directly.
3581 *
3582 * @param[in] node Data node, whose conditional reference, if such, is being decided.
3583 * @param[in] first Whether this is the first resolution to try.
3584 * @param[in] line Line in the input file.
3585 *
3586 * @return EXIT_SUCCESS on pass, EXIT_FAILURE on fail, -1 on error.
3587 */
3588static int
3589resolve_when(struct lyd_node *node, int first, uint32_t line)
3590{
3591 struct lyd_node *ctx_node = NULL;
3592 struct lys_node *parent;
3593 struct lyxp_set set;
3594
3595 assert(node);
3596 memset(&set, 0, sizeof set);
3597
3598 if (!(node->schema->nodetype & (LYS_NOTIF | LYS_RPC)) && (((struct lys_node_container *)node->schema)->when)) {
Michal Vaskoe1fe43d2015-10-29 11:09:59 +01003599 if (lyxp_eval(((struct lys_node_container *)node->schema)->when->cond, node, &set, 1, line)) {
Michal Vaskocf024702015-10-08 15:01:42 +02003600 return -1;
3601 }
3602
Michal Vaskoe1fe43d2015-10-29 11:09:59 +01003603 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, node, 1);
Michal Vaskocf024702015-10-08 15:01:42 +02003604
3605 if (!set.value.bool) {
3606 if (!first) {
Radek Krejciadb57612016-02-16 13:34:34 +01003607 LOGVAL(LYE_NOCOND, line, LY_VLOG_LYS, node, "When", ((struct lys_node_container *)node->schema)->when->cond);
Michal Vaskocf024702015-10-08 15:01:42 +02003608 }
3609 return 1;
3610 }
3611 }
3612
3613 parent = node->schema;
3614 goto check_augment;
3615
3616 /* check when in every schema node that affects node */
3617 while (parent && (parent->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE))) {
3618 if (((struct lys_node_uses *)parent)->when) {
3619 if (!ctx_node) {
3620 ctx_node = resolve_when_ctx_node(node, parent);
3621 if (!ctx_node) {
3622 LOGINT;
3623 return -1;
3624 }
3625 }
Michal Vaskoe1fe43d2015-10-29 11:09:59 +01003626 if (lyxp_eval(((struct lys_node_uses *)parent)->when->cond, ctx_node, &set, 1, line)) {
Michal Vaskocf024702015-10-08 15:01:42 +02003627 return -1;
3628 }
3629
Michal Vaskoe1fe43d2015-10-29 11:09:59 +01003630 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, ctx_node, 1);
Michal Vaskocf024702015-10-08 15:01:42 +02003631
3632 if (!set.value.bool) {
3633 if (!first) {
Radek Krejciadb57612016-02-16 13:34:34 +01003634 LOGVAL(LYE_NOCOND, line, LY_VLOG_LYS, node, "When", ((struct lys_node_uses *)parent)->when->cond);
Michal Vaskocf024702015-10-08 15:01:42 +02003635 }
3636 return 1;
3637 }
3638 }
3639
3640check_augment:
3641 if ((parent->parent && (parent->parent->nodetype == LYS_AUGMENT) && (((struct lys_node_augment *)parent->parent)->when))) {
3642 if (!ctx_node) {
3643 ctx_node = resolve_when_ctx_node(node, parent->parent);
3644 if (!ctx_node) {
3645 LOGINT;
3646 return -1;
3647 }
3648 }
Michal Vaskoe1fe43d2015-10-29 11:09:59 +01003649 if (lyxp_eval(((struct lys_node_augment *)parent->parent)->when->cond, ctx_node, &set, 1, line)) {
Michal Vaskocf024702015-10-08 15:01:42 +02003650 return -1;
3651 }
3652
Michal Vaskoe1fe43d2015-10-29 11:09:59 +01003653 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, ctx_node, 1);
Michal Vaskocf024702015-10-08 15:01:42 +02003654
3655 if (!set.value.bool) {
3656 if (!first) {
Radek Krejciadb57612016-02-16 13:34:34 +01003657 LOGVAL(LYE_NOCOND, line, LY_VLOG_LYS, node, "When", ((struct lys_node_augment *)parent->parent)->when->cond);
Michal Vaskocf024702015-10-08 15:01:42 +02003658 }
3659 return 1;
3660 }
3661 }
3662
3663 parent = lys_parent(parent);
3664 }
3665
3666 return 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003667}
3668
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003669/**
Michal Vaskobb211122015-08-19 14:03:11 +02003670 * @brief Resolve a single unres schema item. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003671 *
3672 * @param[in] mod Main module.
3673 * @param[in] item Item to resolve. Type determined by \p type.
3674 * @param[in] type Type of the unresolved item.
3675 * @param[in] str_snode String, a schema node, or NULL.
Michal Vaskobb211122015-08-19 14:03:11 +02003676 * @param[in] unres Unres schema structure to use.
Michal Vasko407f1bb2015-09-23 15:51:07 +02003677 * @param[in] first Whether this is the first resolution try.
Michal Vasko184521f2015-09-24 13:14:26 +02003678 * @param[in] line Line in the input file. 0 skips line print.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003679 *
3680 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
3681 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003682static int
Michal Vasko0bd29d12015-08-19 11:45:49 +02003683resolve_unres_schema_item(struct lys_module *mod, void *item, enum UNRES_ITEM type, void *str_snode,
Michal Vasko407f1bb2015-09-23 15:51:07 +02003684 struct unres_schema *unres, int first, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003685{
Radek Krejci2f12f852016-01-08 12:59:57 +01003686 int rc = -1, has_str = 0, tpdf_flag = 0;
Michal Vasko563ef092015-09-04 13:17:23 +02003687 struct lys_node *node;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003688 const char *base_name;
3689
3690 struct lys_ident *ident;
3691 struct lys_type *stype;
3692 struct lys_feature **feat_ptr;
3693 struct lys_node_choice *choic;
Michal Vasko88c29542015-11-27 14:57:53 +01003694 struct lyxml_elem *yin;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003695
3696 switch (type) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003697 case UNRES_IDENT:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003698 base_name = str_snode;
3699 ident = item;
3700
Michal Vasko184521f2015-09-24 13:14:26 +02003701 rc = resolve_base_ident(mod, ident, base_name, "ident", first, line, NULL);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003702 has_str = 1;
3703 break;
3704 case UNRES_TYPE_IDENTREF:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003705 base_name = str_snode;
3706 stype = item;
3707
Radek Krejcicf509982015-12-15 09:22:44 +01003708 rc = resolve_base_ident(mod, NULL, base_name, "type", first, line, stype);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003709 has_str = 1;
3710 break;
3711 case UNRES_TYPE_LEAFREF:
Michal Vasko563ef092015-09-04 13:17:23 +02003712 node = str_snode;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003713 stype = item;
3714
Radek Krejci2f12f852016-01-08 12:59:57 +01003715 /* HACK - when there is no parent, we are in top level typedef and in that
3716 * case, the path has to contain absolute path, so we let the resolve_path_arg_schema()
3717 * know it via tpdf_flag */
3718 if (!node) {
3719 tpdf_flag = 1;
3720 node = (struct lys_node *)stype->parent;
3721 }
3722
3723 rc = resolve_path_arg_schema(stype->info.lref.path, node, tpdf_flag, first, line,
Michal Vasko1e62a092015-12-01 12:27:20 +01003724 (const struct lys_node **)&stype->info.lref.target);
Radek Krejci46c4cd72016-01-21 15:13:52 +01003725 if (stype->info.lref.target) {
3726 /* store the backlink from leafref target */
3727 if (!stype->info.lref.target->child) {
3728 stype->info.lref.target->child = (void*)ly_set_new();
3729 if (!stype->info.lref.target->child) {
3730 LOGMEM;
3731 return -1;
3732 }
3733 }
3734 ly_set_add((struct ly_set *)stype->info.lref.target->child, stype->parent);
3735 }
3736
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003737 has_str = 0;
3738 break;
3739 case UNRES_TYPE_DER:
Michal Vasko88c29542015-11-27 14:57:53 +01003740 /* parent */
3741 node = str_snode;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003742 stype = item;
3743
Michal Vasko88c29542015-11-27 14:57:53 +01003744 /* HACK type->der is temporarily unparsed type statement */
3745 yin = (struct lyxml_elem *)stype->der;
3746 stype->der = NULL;
3747
3748 rc = fill_yin_type(mod, node, yin, stype, unres);
3749 if (!rc) {
3750 /* we need to always be able to free this, it's safe only in this case */
Michal Vasko345da0a2015-12-02 10:35:55 +01003751 lyxml_free(mod->ctx, yin);
Michal Vasko88c29542015-11-27 14:57:53 +01003752 } else {
3753 /* may try again later, put all back how it was */
3754 stype->der = (struct lys_tpdf *)yin;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003755 }
Michal Vasko88c29542015-11-27 14:57:53 +01003756 has_str = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003757 break;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003758 case UNRES_IFFEAT:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003759 base_name = str_snode;
3760 feat_ptr = item;
3761
Michal Vasko184521f2015-09-24 13:14:26 +02003762 rc = resolve_feature(base_name, mod, first, line, feat_ptr);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003763 has_str = 1;
3764 break;
3765 case UNRES_USES:
Michal Vasko407f1bb2015-09-23 15:51:07 +02003766 rc = resolve_unres_schema_uses(item, unres, first, line);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003767 has_str = 0;
3768 break;
3769 case UNRES_TYPE_DFLT:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003770 base_name = str_snode;
3771 stype = item;
3772
Michal Vasko1dca6882015-10-22 14:29:42 +02003773 rc = check_default(stype, base_name, first, line);
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003774 /* do not remove base_name (dflt), it's in a typedef */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003775 has_str = 0;
3776 break;
3777 case UNRES_CHOICE_DFLT:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003778 base_name = str_snode;
3779 choic = item;
3780
Michal Vasko7955b362015-09-04 14:18:15 +02003781 choic->dflt = resolve_choice_dflt(choic, base_name);
3782 if (choic->dflt) {
3783 rc = EXIT_SUCCESS;
3784 } else {
3785 rc = EXIT_FAILURE;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02003786 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003787 has_str = 1;
3788 break;
3789 case UNRES_LIST_KEYS:
Michal Vasko36cbaa42015-12-14 13:15:48 +01003790 rc = resolve_list_keys(item, str_snode, first, line);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003791 has_str = 1;
3792 break;
3793 case UNRES_LIST_UNIQ:
Radek Krejci581ce772015-11-10 17:22:40 +01003794 rc = resolve_unique(item, str_snode, first, line);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003795 has_str = 1;
3796 break;
Michal Vasko7178e692016-02-12 15:58:05 +01003797 case UNRES_AUGMENT:
3798 rc = resolve_augment(item, NULL, first, line);
3799 has_str = 0;
3800 break;
Michal Vaskocf024702015-10-08 15:01:42 +02003801 default:
3802 LOGINT;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003803 break;
3804 }
3805
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003806 if (has_str && !rc) {
3807 lydict_remove(mod->ctx, str_snode);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003808 }
3809
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003810 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003811}
3812
Michal Vaskof02e3742015-08-05 16:27:02 +02003813/* logs directly */
3814static void
Michal Vasko0bd29d12015-08-19 11:45:49 +02003815print_unres_schema_item_fail(void *item, enum UNRES_ITEM type, void *str_node, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003816{
Michal Vaskof02e3742015-08-05 16:27:02 +02003817 char line_str[18];
3818
3819 if (line) {
3820 sprintf(line_str, " (line %u)", line);
3821 } else {
3822 line_str[0] = '\0';
3823 }
3824
3825 switch (type) {
Michal Vaskof02e3742015-08-05 16:27:02 +02003826 case UNRES_IDENT:
Radek Krejci1d82ef62015-08-07 14:44:40 +02003827 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "identity", (char *)str_node, line_str);
Michal Vaskof02e3742015-08-05 16:27:02 +02003828 break;
3829 case UNRES_TYPE_IDENTREF:
Radek Krejci1d82ef62015-08-07 14:44:40 +02003830 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "identityref", (char *)str_node, line_str);
Michal Vaskof02e3742015-08-05 16:27:02 +02003831 break;
3832 case UNRES_TYPE_LEAFREF:
3833 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "leafref", ((struct lys_type *)item)->info.lref.path, line_str);
3834 break;
3835 case UNRES_TYPE_DER:
Michal Vasko88c29542015-11-27 14:57:53 +01003836 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "derived type",
3837 ((struct lyxml_elem *)((struct lys_type *)item)->der)->attr->value, line_str);
Michal Vaskof02e3742015-08-05 16:27:02 +02003838 break;
Michal Vaskof02e3742015-08-05 16:27:02 +02003839 case UNRES_IFFEAT:
Radek Krejci1d82ef62015-08-07 14:44:40 +02003840 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "if-feature", (char *)str_node, line_str);
Michal Vaskof02e3742015-08-05 16:27:02 +02003841 break;
3842 case UNRES_USES:
3843 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "uses", ((struct lys_node_uses *)item)->name, line_str);
3844 break;
3845 case UNRES_TYPE_DFLT:
Radek Krejci1d82ef62015-08-07 14:44:40 +02003846 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "type default", (char *)str_node, line_str);
Michal Vaskof02e3742015-08-05 16:27:02 +02003847 break;
3848 case UNRES_CHOICE_DFLT:
Radek Krejci1d82ef62015-08-07 14:44:40 +02003849 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "choice default", (char *)str_node, line_str);
Michal Vaskof02e3742015-08-05 16:27:02 +02003850 break;
3851 case UNRES_LIST_KEYS:
Radek Krejci1d82ef62015-08-07 14:44:40 +02003852 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "list keys", (char *)str_node, line_str);
Michal Vaskof02e3742015-08-05 16:27:02 +02003853 break;
3854 case UNRES_LIST_UNIQ:
Radek Krejci1d82ef62015-08-07 14:44:40 +02003855 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "list unique", (char *)str_node, line_str);
Michal Vaskof02e3742015-08-05 16:27:02 +02003856 break;
Michal Vasko7178e692016-02-12 15:58:05 +01003857 case UNRES_AUGMENT:
Michal Vasko729d2912016-02-12 16:01:43 +01003858 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "augment target", ((struct lys_node_augment *)item)->target_name, line_str);
Michal Vasko7178e692016-02-12 15:58:05 +01003859 break;
Michal Vaskocf024702015-10-08 15:01:42 +02003860 default:
3861 LOGINT;
Michal Vaskof02e3742015-08-05 16:27:02 +02003862 break;
3863 }
3864}
3865
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003866/**
Michal Vaskobb211122015-08-19 14:03:11 +02003867 * @brief Resolve every unres schema item in the structure. Logs directly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003868 *
3869 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02003870 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003871 *
Michal Vasko92b8a382015-08-19 14:03:49 +02003872 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003873 */
Michal Vaskof02e3742015-08-05 16:27:02 +02003874int
Michal Vasko0bd29d12015-08-19 11:45:49 +02003875resolve_unres_schema(struct lys_module *mod, struct unres_schema *unres)
Michal Vaskof02e3742015-08-05 16:27:02 +02003876{
Michal Vasko88c29542015-11-27 14:57:53 +01003877 uint32_t i, resolved, unres_count, res_count;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003878 int rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003879
3880 assert(unres);
3881
Michal Vasko51054ca2015-08-12 12:20:00 +02003882 resolved = 0;
3883
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003884 /* uses */
Michal Vasko51054ca2015-08-12 12:20:00 +02003885 do {
Michal Vasko88c29542015-11-27 14:57:53 +01003886 unres_count = 0;
3887 res_count = 0;
Michal Vasko51054ca2015-08-12 12:20:00 +02003888
3889 for (i = 0; i < unres->count; ++i) {
Michal Vasko88c29542015-11-27 14:57:53 +01003890 /* we do not need to have UNRES_TYPE_IDENTREF or UNRES_TYPE_LEAFREF resolved,
3891 * we need every type's base only */
3892 if ((unres->type[i] != UNRES_USES) && (unres->type[i] != UNRES_TYPE_DER)) {
Michal Vasko51054ca2015-08-12 12:20:00 +02003893 continue;
3894 }
3895
Michal Vasko88c29542015-11-27 14:57:53 +01003896 ++unres_count;
Michal Vasko407f1bb2015-09-23 15:51:07 +02003897 rc = resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres, 0,
3898 LOGLINE_IDX(unres, i));
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003899 if (!rc) {
Michal Vasko51054ca2015-08-12 12:20:00 +02003900 unres->type[i] = UNRES_RESOLVED;
3901 ++resolved;
Michal Vasko88c29542015-11-27 14:57:53 +01003902 ++res_count;
Michal Vasko89e15322015-08-17 15:46:55 +02003903 } else if (rc == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003904 return -1;
Michal Vasko51054ca2015-08-12 12:20:00 +02003905 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003906 }
Michal Vasko88c29542015-11-27 14:57:53 +01003907 } while (res_count && (res_count < unres_count));
Michal Vasko51054ca2015-08-12 12:20:00 +02003908
Michal Vasko88c29542015-11-27 14:57:53 +01003909 if (res_count < unres_count) {
Radek Krejciadb57612016-02-16 13:34:34 +01003910 LOGVAL(LYE_SPEC, 0, 0, NULL, "There are unresolved uses left.");
Michal Vasko92b8a382015-08-19 14:03:49 +02003911 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003912 }
3913
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003914 /* the rest */
3915 for (i = 0; i < unres->count; ++i) {
3916 if (unres->type[i] == UNRES_RESOLVED) {
3917 continue;
3918 }
Michal Vaskoc07187d2015-08-13 15:20:57 +02003919
Michal Vasko407f1bb2015-09-23 15:51:07 +02003920 rc = resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres, 0,
3921 LOGLINE_IDX(unres, i));
Michal Vasko184521f2015-09-24 13:14:26 +02003922 if (rc) {
3923 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003924 }
Michal Vasko184521f2015-09-24 13:14:26 +02003925
3926 unres->type[i] = UNRES_RESOLVED;
3927 ++resolved;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003928 }
3929
3930 if (resolved < unres->count) {
Radek Krejciadb57612016-02-16 13:34:34 +01003931 LOGVAL(LYE_SPEC, 0, 0, NULL, "There are unresolved schema items left.");
Michal Vasko92b8a382015-08-19 14:03:49 +02003932 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003933 }
3934
Radek Krejcic071c542016-01-27 14:57:51 +01003935 unres->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003936 return EXIT_SUCCESS;
3937}
3938
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003939/**
Michal Vaskobb211122015-08-19 14:03:11 +02003940 * @brief Try to resolve an unres schema item with a string argument. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003941 *
3942 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02003943 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003944 * @param[in] item Item to resolve. Type determined by \p type.
3945 * @param[in] type Type of the unresolved item.
3946 * @param[in] str String argument.
3947 * @param[in] line Line in the input file.
3948 *
3949 * @return EXIT_SUCCESS on success or storing the item in unres, -1 on error.
3950 */
3951int
Michal Vasko0bd29d12015-08-19 11:45:49 +02003952unres_schema_add_str(struct lys_module *mod, struct unres_schema *unres, void *item, enum UNRES_ITEM type, const char *str,
Michal Vasko7955b362015-09-04 14:18:15 +02003953 uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003954{
3955 str = lydict_insert(mod->ctx, str, 0);
Michal Vasko0bd29d12015-08-19 11:45:49 +02003956 return unres_schema_add_node(mod, unres, item, type, (struct lys_node *)str, line);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003957}
3958
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003959/**
Michal Vaskobb211122015-08-19 14:03:11 +02003960 * @brief Try to resolve an unres schema item with a schema node argument. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003961 *
3962 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02003963 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003964 * @param[in] item Item to resolve. Type determined by \p type.
Michal Vasko88c29542015-11-27 14:57:53 +01003965 * @param[in] type Type of the unresolved item. UNRES_TYPE_DER is handled specially!
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003966 * @param[in] snode Schema node argument.
3967 * @param[in] line Line in the input file.
3968 *
3969 * @return EXIT_SUCCESS on success or storing the item in unres, -1 on error.
3970 */
3971int
Michal Vasko0bd29d12015-08-19 11:45:49 +02003972unres_schema_add_node(struct lys_module *mod, struct unres_schema *unres, void *item, enum UNRES_ITEM type,
Michal Vasko7955b362015-09-04 14:18:15 +02003973 struct lys_node *snode, uint32_t line)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003974{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003975 int rc;
Michal Vasko88c29542015-11-27 14:57:53 +01003976 struct lyxml_elem *yin;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003977
Michal Vasko9bf425b2015-10-22 11:42:03 +02003978 assert(unres && item && ((type != UNRES_LEAFREF) && (type != UNRES_INSTID) && (type != UNRES_WHEN)
3979 && (type != UNRES_MUST)));
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003980
Michal Vasko184521f2015-09-24 13:14:26 +02003981 rc = resolve_unres_schema_item(mod, item, type, snode, unres, 1, line);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003982 if (rc != EXIT_FAILURE) {
3983 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003984 }
3985
Michal Vasko0bd29d12015-08-19 11:45:49 +02003986 print_unres_schema_item_fail(item, type, snode, line);
Michal Vaskof02e3742015-08-05 16:27:02 +02003987
Michal Vasko88c29542015-11-27 14:57:53 +01003988 /* HACK unlinking is performed here so that we do not do any (NS) copying in vain */
3989 if (type == UNRES_TYPE_DER) {
3990 yin = (struct lyxml_elem *)((struct lys_type *)item)->der;
3991 lyxml_unlink_elem(mod->ctx, yin, 1);
3992 ((struct lys_type *)item)->der = (struct lys_tpdf *)yin;
3993 }
3994
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003995 unres->count++;
Michal Vasko253035f2015-12-17 16:58:13 +01003996 unres->item = ly_realloc(unres->item, unres->count*sizeof *unres->item);
3997 if (!unres->item) {
3998 LOGMEM;
3999 return -1;
4000 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004001 unres->item[unres->count-1] = item;
Michal Vasko253035f2015-12-17 16:58:13 +01004002 unres->type = ly_realloc(unres->type, unres->count*sizeof *unres->type);
4003 if (!unres->type) {
4004 LOGMEM;
4005 return -1;
4006 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004007 unres->type[unres->count-1] = type;
Michal Vasko253035f2015-12-17 16:58:13 +01004008 unres->str_snode = ly_realloc(unres->str_snode, unres->count*sizeof *unres->str_snode);
4009 if (!unres->str_snode) {
4010 LOGMEM;
4011 return -1;
4012 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004013 unres->str_snode[unres->count-1] = snode;
Radek Krejcic071c542016-01-27 14:57:51 +01004014 unres->module = ly_realloc(unres->module, unres->count*sizeof *unres->module);
4015 if (!unres->module) {
4016 LOGMEM;
4017 return -1;
4018 }
4019 unres->module[unres->count-1] = mod;
Michal Vaskoc07187d2015-08-13 15:20:57 +02004020#ifndef NDEBUG
Michal Vasko253035f2015-12-17 16:58:13 +01004021 unres->line = ly_realloc(unres->line, unres->count*sizeof *unres->line);
4022 if (!unres->line) {
4023 LOGMEM;
4024 return -1;
4025 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004026 unres->line[unres->count-1] = line;
Michal Vaskoc07187d2015-08-13 15:20:57 +02004027#endif
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004028
4029 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004030}
4031
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004032/**
Michal Vaskobb211122015-08-19 14:03:11 +02004033 * @brief Duplicate an unres schema item. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004034 *
4035 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02004036 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004037 * @param[in] item Old item to be resolved.
4038 * @param[in] type Type of the old unresolved item.
4039 * @param[in] new_item New item to use in the duplicate.
4040 *
4041 * @return EXIT_SUCCESS on success, -1 on error.
4042 */
Michal Vaskodad19402015-08-06 09:51:53 +02004043int
Michal Vasko0bd29d12015-08-19 11:45:49 +02004044unres_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 +02004045{
4046 int i;
4047
Michal Vaskocf024702015-10-08 15:01:42 +02004048 assert(item && new_item && ((type != UNRES_LEAFREF) && (type != UNRES_INSTID) && (type != UNRES_WHEN)));
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004049
Michal Vasko0bd29d12015-08-19 11:45:49 +02004050 i = unres_schema_find(unres, item, type);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004051
4052 if (i == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004053 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004054 }
4055
Michal Vasko0d204592015-10-07 09:50:04 +02004056 if ((type == UNRES_TYPE_LEAFREF) || (type == UNRES_USES) || (type == UNRES_TYPE_DFLT)) {
Michal Vasko0bd29d12015-08-19 11:45:49 +02004057 if (unres_schema_add_node(mod, unres, new_item, type, unres->str_snode[i], 0) == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004058 LOGINT;
4059 return -1;
4060 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004061 } else {
Michal Vasko0bd29d12015-08-19 11:45:49 +02004062 if (unres_schema_add_str(mod, unres, new_item, type, unres->str_snode[i], 0) == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004063 LOGINT;
4064 return -1;
4065 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004066 }
Michal Vaskodad19402015-08-06 09:51:53 +02004067
4068 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004069}
4070
Michal Vaskof02e3742015-08-05 16:27:02 +02004071/* does not log */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004072int
Michal Vasko0bd29d12015-08-19 11:45:49 +02004073unres_schema_find(struct unres_schema *unres, void *item, enum UNRES_ITEM type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004074{
4075 uint32_t ret = -1, i;
4076
4077 for (i = 0; i < unres->count; ++i) {
4078 if ((unres->item[i] == item) && (unres->type[i] == type)) {
4079 ret = i;
4080 break;
4081 }
4082 }
4083
4084 return ret;
4085}
Michal Vasko8bcdf292015-08-19 14:04:43 +02004086
Michal Vasko88c29542015-11-27 14:57:53 +01004087void
Radek Krejcic071c542016-01-27 14:57:51 +01004088unres_schema_free(struct lys_module *module, struct unres_schema **unres)
Michal Vasko88c29542015-11-27 14:57:53 +01004089{
4090 uint32_t i;
Radek Krejcic071c542016-01-27 14:57:51 +01004091 unsigned int unresolved = 0;
Michal Vasko88c29542015-11-27 14:57:53 +01004092
Radek Krejcic071c542016-01-27 14:57:51 +01004093 if (!unres || !(*unres)) {
4094 return;
Michal Vasko88c29542015-11-27 14:57:53 +01004095 }
4096
Radek Krejcic071c542016-01-27 14:57:51 +01004097 assert(module || (*unres)->count == 0);
4098
4099 for (i = 0; i < (*unres)->count; ++i) {
4100 if ((*unres)->module[i] != module) {
4101 if ((*unres)->type[i] != UNRES_RESOLVED) {
4102 unresolved++;
4103 }
4104 continue;
4105 }
4106 if ((*unres)->type[i] == UNRES_TYPE_DER) {
4107 lyxml_free(module->ctx, (struct lyxml_elem *)((struct lys_type *)(*unres)->item[i])->der);
4108 }
4109 (*unres)->type[i] = UNRES_RESOLVED;
4110 }
4111
4112 if (!module || (!unresolved && !module->type)) {
4113 free((*unres)->item);
4114 free((*unres)->type);
4115 free((*unres)->str_snode);
4116 free((*unres)->module);
Michal Vasko88c29542015-11-27 14:57:53 +01004117#ifndef NDEBUG
Radek Krejcic071c542016-01-27 14:57:51 +01004118 free((*unres)->line);
Michal Vasko88c29542015-11-27 14:57:53 +01004119#endif
Radek Krejcic071c542016-01-27 14:57:51 +01004120 free((*unres));
4121 (*unres) = NULL;
4122 }
Michal Vasko88c29542015-11-27 14:57:53 +01004123}
4124
Michal Vasko8bcdf292015-08-19 14:04:43 +02004125/* logs directly */
4126static void
Michal Vaskocf024702015-10-08 15:01:42 +02004127print_unres_data_item_fail(struct lyd_node *node, enum UNRES_ITEM type, uint32_t line)
Michal Vasko8bcdf292015-08-19 14:04:43 +02004128{
4129 struct lys_node_leaf *sleaf;
4130 char line_str[18];
4131
4132 if (line) {
4133 sprintf(line_str, " (line %u)", line);
4134 } else {
4135 line_str[0] = '\0';
4136 }
4137
Michal Vaskocf024702015-10-08 15:01:42 +02004138 sleaf = (struct lys_node_leaf *)node->schema;
Michal Vasko8bcdf292015-08-19 14:04:43 +02004139
Michal Vaskocf024702015-10-08 15:01:42 +02004140 switch (type) {
4141 case UNRES_LEAFREF:
Michal Vasko8bcdf292015-08-19 14:04:43 +02004142 LOGVRB("Leafref \"%s\" could not be resolved, it will be attempted later%s.",
4143 sleaf->type.info.lref.path, line_str);
Michal Vaskocf024702015-10-08 15:01:42 +02004144 break;
4145 case UNRES_INSTID:
Michal Vasko8bcdf292015-08-19 14:04:43 +02004146 LOGVRB("Instance-identifier \"%s\" could not be resolved, it will be attempted later%s.",
Michal Vasko83a6c462015-10-08 16:43:53 +02004147 ((struct lyd_node_leaf_list *)node)->value_str, line_str);
Michal Vaskocf024702015-10-08 15:01:42 +02004148 break;
4149 case UNRES_WHEN:
4150 LOGVRB("There was an unsatisfied when condition, evaluation will be attempted later%s.", line_str);
4151 break;
Michal Vaskobf19d252015-10-08 15:39:17 +02004152 case UNRES_MUST:
4153 LOGVRB("There was an unsatisfied must condition, evaluation will be attempted later%s.", line_str);
4154 break;
Michal Vaskocf024702015-10-08 15:01:42 +02004155 default:
4156 LOGINT;
4157 break;
Michal Vasko8bcdf292015-08-19 14:04:43 +02004158 }
4159}
4160
4161/**
4162 * @brief Resolve a single unres data item. Logs directly.
4163 *
Michal Vaskocf024702015-10-08 15:01:42 +02004164 * @param[in] node Data node to resolve.
Michal Vasko184521f2015-09-24 13:14:26 +02004165 * @param[in] first Whether this is the first resolution try.
Michal Vaskocf024702015-10-08 15:01:42 +02004166 * @param[in] type Type of the unresolved item.
Michal Vasko184521f2015-09-24 13:14:26 +02004167 * @param[in] line Line in the input file. 0 skips line print.
Michal Vasko8bcdf292015-08-19 14:04:43 +02004168 *
4169 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
4170 */
Michal Vasko8ea2b7f2015-09-29 14:30:53 +02004171int
Michal Vaskocf024702015-10-08 15:01:42 +02004172resolve_unres_data_item(struct lyd_node *node, enum UNRES_ITEM type, int first, uint32_t line)
Michal Vasko8bcdf292015-08-19 14:04:43 +02004173{
4174 uint32_t i;
Michal Vasko0491ab32015-08-19 14:28:29 +02004175 int rc;
Michal Vasko83a6c462015-10-08 16:43:53 +02004176 struct lyd_node_leaf_list *leaf;
Michal Vasko8bcdf292015-08-19 14:04:43 +02004177 struct lys_node_leaf *sleaf;
4178 struct unres_data matches;
4179
4180 memset(&matches, 0, sizeof matches);
Michal Vasko83a6c462015-10-08 16:43:53 +02004181 leaf = (struct lyd_node_leaf_list *)node;
Michal Vaskocf024702015-10-08 15:01:42 +02004182 sleaf = (struct lys_node_leaf *)leaf->schema;
Michal Vasko8bcdf292015-08-19 14:04:43 +02004183
Michal Vaskocf024702015-10-08 15:01:42 +02004184 switch (type) {
4185 case UNRES_LEAFREF:
4186 assert(sleaf->type.base == LY_TYPE_LEAFREF);
Michal Vaskof7677612015-10-16 14:27:23 +02004187 if ((rc = resolve_path_arg_data(node, sleaf->type.info.lref.path, first, line, &matches))) {
Michal Vasko0491ab32015-08-19 14:28:29 +02004188 return rc;
Michal Vasko8bcdf292015-08-19 14:04:43 +02004189 }
4190
4191 /* check that value matches */
4192 for (i = 0; i < matches.count; ++i) {
Michal Vasko83a6c462015-10-08 16:43:53 +02004193 if (leaf->value_str == ((struct lyd_node_leaf_list *)matches.node[i])->value_str) {
Michal Vaskocf024702015-10-08 15:01:42 +02004194 leaf->value.leafref = matches.node[i];
Michal Vasko8bcdf292015-08-19 14:04:43 +02004195 break;
4196 }
4197 }
4198
Michal Vaskocf024702015-10-08 15:01:42 +02004199 free(matches.node);
Michal Vasko8bcdf292015-08-19 14:04:43 +02004200 memset(&matches, 0, sizeof matches);
4201
Michal Vaskocf024702015-10-08 15:01:42 +02004202 if (!leaf->value.leafref) {
Michal Vasko8bcdf292015-08-19 14:04:43 +02004203 /* reference not found */
Michal Vasko184521f2015-09-24 13:14:26 +02004204 if (!first) {
Radek Krejciadb57612016-02-16 13:34:34 +01004205 LOGVAL(LYE_SPEC, line, LY_VLOG_LYD, leaf, "Leafref \"%s\" value \"%s\" did not match any node value.",
Michal Vaskocf024702015-10-08 15:01:42 +02004206 sleaf->type.info.lref.path, leaf->value_str);
Michal Vasko184521f2015-09-24 13:14:26 +02004207 }
Michal Vasko8bcdf292015-08-19 14:04:43 +02004208 return EXIT_FAILURE;
4209 }
Michal Vaskocf024702015-10-08 15:01:42 +02004210 break;
Michal Vasko8bcdf292015-08-19 14:04:43 +02004211
Michal Vaskocf024702015-10-08 15:01:42 +02004212 case UNRES_INSTID:
4213 assert(sleaf->type.base == LY_TYPE_INST);
Michal Vasko8bcdf292015-08-19 14:04:43 +02004214 ly_errno = 0;
Radek Krejci40f17b92016-02-03 14:30:43 +01004215 leaf->value.instance = resolve_instid(node, leaf->value_str, line);
4216 if (!leaf->value.instance) {
Michal Vasko8bcdf292015-08-19 14:04:43 +02004217 if (ly_errno) {
4218 return -1;
4219 } else if (sleaf->type.info.inst.req > -1) {
Michal Vasko184521f2015-09-24 13:14:26 +02004220 if (!first) {
Radek Krejciadb57612016-02-16 13:34:34 +01004221 LOGVAL(LYE_SPEC, line, LY_VLOG_LYD, leaf, "There is no instance of \"%s\".", leaf->value_str);
Michal Vasko184521f2015-09-24 13:14:26 +02004222 }
Michal Vasko8bcdf292015-08-19 14:04:43 +02004223 return EXIT_FAILURE;
4224 } else {
Radek Krejci4ce42be2016-02-03 13:04:41 +01004225 LOGVRB("There is no instance of \"%s\", but it is not required.", leaf->value_str);
Michal Vasko8bcdf292015-08-19 14:04:43 +02004226 }
4227 }
Michal Vaskocf024702015-10-08 15:01:42 +02004228 break;
4229
4230 case UNRES_WHEN:
4231 if ((rc = resolve_when(node, first, line))) {
4232 return rc;
4233 }
4234 break;
4235
Michal Vaskobf19d252015-10-08 15:39:17 +02004236 case UNRES_MUST:
4237 if ((rc = resolve_must(node, first, line))) {
4238 return rc;
4239 }
4240 break;
4241
Michal Vaskocf024702015-10-08 15:01:42 +02004242 default:
Michal Vasko8bcdf292015-08-19 14:04:43 +02004243 LOGINT;
4244 return -1;
4245 }
4246
4247 return EXIT_SUCCESS;
4248}
4249
4250/**
4251 * @brief Try to resolve an unres data item. Logs indirectly.
4252 *
4253 * @param[in] unres Unres data structure to use.
Michal Vaskocf024702015-10-08 15:01:42 +02004254 * @param[in] node Data node to use.
Michal Vasko8bcdf292015-08-19 14:04:43 +02004255 * @param[in] line Line in the input file.
4256 *
4257 * @return EXIT_SUCCESS on success or storing the item in unres, -1 on error.
4258 */
4259int
Michal Vaskocf024702015-10-08 15:01:42 +02004260unres_data_add(struct unres_data *unres, struct lyd_node *node, enum UNRES_ITEM type, uint32_t line)
Michal Vasko8bcdf292015-08-19 14:04:43 +02004261{
4262 int rc;
4263
Michal Vaskobf19d252015-10-08 15:39:17 +02004264 assert(unres && node && ((type == UNRES_LEAFREF) || (type == UNRES_INSTID) || (type == UNRES_WHEN) || (type == UNRES_MUST)));
Michal Vasko8bcdf292015-08-19 14:04:43 +02004265
Michal Vaskocf024702015-10-08 15:01:42 +02004266 rc = resolve_unres_data_item(node, type, 1, line);
Michal Vasko8bcdf292015-08-19 14:04:43 +02004267 if (rc != EXIT_FAILURE) {
4268 return rc;
4269 }
4270
Michal Vaskocf024702015-10-08 15:01:42 +02004271 print_unres_data_item_fail(node, type, line);
Michal Vasko8bcdf292015-08-19 14:04:43 +02004272
4273 ++unres->count;
Michal Vasko253035f2015-12-17 16:58:13 +01004274 unres->node = ly_realloc(unres->node, unres->count * sizeof *unres->node);
4275 if (!unres->node) {
4276 LOGMEM;
4277 return -1;
4278 }
Michal Vaskocf024702015-10-08 15:01:42 +02004279 unres->node[unres->count - 1] = node;
Michal Vasko253035f2015-12-17 16:58:13 +01004280 unres->type = ly_realloc(unres->type, unres->count * sizeof *unres->type);
4281 if (!unres->type) {
4282 LOGMEM;
4283 return -1;
4284 }
Michal Vaskocf024702015-10-08 15:01:42 +02004285 unres->type[unres->count - 1] = type;
Michal Vasko8bcdf292015-08-19 14:04:43 +02004286#ifndef NDEBUG
Michal Vasko253035f2015-12-17 16:58:13 +01004287 unres->line = ly_realloc(unres->line, unres->count * sizeof *unres->line);
4288 if (!unres->line) {
4289 LOGMEM;
4290 return -1;
4291 }
Michal Vaskocf024702015-10-08 15:01:42 +02004292 unres->line[unres->count - 1] = line;
Michal Vasko8bcdf292015-08-19 14:04:43 +02004293#endif
4294
4295 return EXIT_SUCCESS;
4296}
4297
4298/**
4299 * @brief Resolve every unres data item in the structure. Logs directly.
4300 *
4301 * @param[in] unres Unres data structure to use.
4302 *
4303 * @return EXIT_SUCCESS on success, -1 on error.
4304 */
4305int
4306resolve_unres_data(struct unres_data *unres)
4307{
4308 uint32_t i;
4309 int rc;
4310
4311 for (i = 0; i < unres->count; ++i) {
Michal Vaskocf024702015-10-08 15:01:42 +02004312 rc = resolve_unres_data_item(unres->node[i], unres->type[i], 0, LOGLINE_IDX(unres, i));
Michal Vasko8bcdf292015-08-19 14:04:43 +02004313 if (rc) {
Radek Krejciadb57612016-02-16 13:34:34 +01004314 LOGVAL(LYE_SPEC, 0, 0, NULL, "There are unresolved data items left.");
Michal Vasko8bcdf292015-08-19 14:04:43 +02004315 return -1;
4316 }
4317 }
4318
4319 return EXIT_SUCCESS;
4320}