blob: c9ef10fb4c5dceb94c95f42a048a9599f9000074 [file] [log] [blame]
Radek Krejcie7b95092019-05-15 11:03:07 +02001/**
2 * @file tree_schema.c
3 * @author Radek Krejci <rkrejci@cesnet.cz>
4 * @brief Schema tree implementation
5 *
6 * Copyright (c) 2015 - 2018 CESNET, z.s.p.o.
7 *
8 * This source code is licensed under BSD 3-Clause License (the "License").
9 * You may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * https://opensource.org/licenses/BSD-3-Clause
13 */
14
15#include "common.h"
16
Radek Krejci084289f2019-07-09 17:35:30 +020017#include <assert.h>
Radek Krejcie7b95092019-05-15 11:03:07 +020018#include <ctype.h>
19#include <errno.h>
20#include <fcntl.h>
21#include <stdarg.h>
22#include <stdint.h>
23#include <string.h>
24#include <unistd.h>
25
26#include "log.h"
27#include "tree.h"
28#include "tree_data.h"
29#include "tree_data_internal.h"
30#include "tree_schema.h"
31
Radek Krejci576b23f2019-07-12 14:06:32 +020032API void
33lyd_trees_free(const struct lyd_node **trees, int free_data)
34{
35 if (!trees) {
36 return;
37 }
38
39 if (free_data) {
40 unsigned int u;
41 LY_ARRAY_FOR(trees, u) {
42 lyd_free_all((struct lyd_node *)trees[u]);
43 }
44 }
45 LY_ARRAY_FREE(trees);
46}
47
48static const struct lyd_node *
49lyd_trees_getstart(const struct lyd_node *tree)
50{
51 if (!tree) {
52 return NULL;
53 }
54 while (tree->prev->next) {
55 tree = tree->prev;
56 }
57 return tree;
58}
59
60API const struct lyd_node **
61lyd_trees_new(size_t count, const struct lyd_node *tree, ...)
62{
63 LY_ERR ret;
64 const struct lyd_node **trees = NULL;
65 va_list ap;
66
67 LY_CHECK_ARG_RET(NULL, tree, count > 0, NULL);
68
69 va_start(ap, tree);
70
71 LY_ARRAY_CREATE_GOTO(tree->schema->module->ctx, trees, count, ret, error);
72 /* first, mandatory, tree to insert */
73 trees[0] = lyd_trees_getstart(tree);
74 LY_ARRAY_INCREMENT(trees);
75
76 /* variable arguments */
77 for (unsigned int u = 1; u < count; ++u) {
78 trees[u] = lyd_trees_getstart(va_arg(ap, const struct lyd_node *));
79 LY_ARRAY_INCREMENT(trees);
80 }
81
82 va_end(ap);
83 return trees;
84
85error:
86 (void)ret; /* unused */
87 lyd_trees_free(trees, 1);
88 va_end(ap);
89 return NULL;
90}
91
Radek Krejcie7b95092019-05-15 11:03:07 +020092static int
Radek Krejci357398c2019-05-27 14:15:01 +020093cmp_str(const char *refstr, const char *str, size_t str_len)
Radek Krejcie7b95092019-05-15 11:03:07 +020094{
95
Radek Krejci357398c2019-05-27 14:15:01 +020096 if (str_len) {
97 int r = strncmp(refstr, str, str_len);
98 if (!r && !refstr[str_len]) {
Radek Krejcie7b95092019-05-15 11:03:07 +020099 return 0;
100 } else {
101 return 1;
102 }
103 } else {
104 return strcmp(refstr, str);
105 }
106}
107
108API const struct lyd_node *
109lyd_search(const struct lyd_node *first, const struct lys_module *module,
110 const char *name, size_t name_len, uint16_t nodetype, const char *value, size_t value_len)
111{
112 const struct lyd_node *node = NULL;
113 const struct lysc_node *snode;
114
115 LY_CHECK_ARG_RET(NULL, module, name, NULL);
116 if (!nodetype) {
117 nodetype = 0xffff;
118 }
119
120 LY_LIST_FOR(first, node) {
121 snode = node->schema;
122 if (!(snode->nodetype & nodetype)) {
123 continue;
124 }
125 if (snode->module != module) {
126 continue;
127 }
128
129 if (cmp_str(snode->name, name, name_len)) {
130 continue;
131 }
132
133 if (value) {
134 if (snode->nodetype == LYS_LIST) {
135 /* TODO handle value as keys of the list instance */
136 } else if (snode->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
137 if (cmp_str(((struct lyd_node_term*)node)->value.canonized, value, value_len)) {
138 continue;
139 }
140 } else {
141 continue;
142 }
143 }
144
145 /* all criteria passed */
146 return node;
147 }
148 return NULL;
149}
150
Radek Krejci084289f2019-07-09 17:35:30 +0200151LY_ERR
Radek Krejci3c9758d2019-07-11 16:49:10 +0200152lyd_value_parse(struct lyd_node_term *node, const char *value, size_t value_len, int dynamic, int second,
Radek Krejci576b23f2019-07-12 14:06:32 +0200153 ly_clb_resolve_prefix get_prefix, void *parser, LYD_FORMAT format, const struct lyd_node **trees)
Radek Krejci084289f2019-07-09 17:35:30 +0200154{
155 LY_ERR ret = LY_SUCCESS, rc;
156 struct ly_err_item *err = NULL;
157 struct ly_ctx *ctx;
158 struct lysc_type *type;
Radek Krejci3c9758d2019-07-11 16:49:10 +0200159 int options = LY_TYPE_OPTS_STORE | (second ? LY_TYPE_OPTS_SECOND_CALL : 0) |
160 (dynamic ? LY_TYPE_OPTS_DYNAMIC : 0) | (trees ? 0 : LY_TYPE_OPTS_INCOMPLETE_DATA);
Radek Krejci084289f2019-07-09 17:35:30 +0200161 assert(node);
162
163 ctx = node->schema->module->ctx;
Radek Krejci084289f2019-07-09 17:35:30 +0200164
Radek Krejci73dead22019-07-11 16:46:16 +0200165 type = ((struct lysc_node_leaf*)node->schema)->type;
166 node->value.plugin = type->plugin;
167 rc = type->plugin->store(ctx, type, value, value_len, options, get_prefix, parser, format,
168 trees ? (void*)node : (void*)node->schema, trees,
169 &node->value, NULL, &err);
170 if (rc == LY_EINCOMPLETE) {
171 ret = rc;
172 /* continue with storing, just remember what to return if storing is ok */
173 } else if (rc) {
174 ret = rc;
175 if (err) {
176 ly_err_print(err);
177 LOGVAL(ctx, LY_VLOG_STR, err->path, err->vecode, err->msg);
178 ly_err_free(err);
Radek Krejci084289f2019-07-09 17:35:30 +0200179 }
Radek Krejci73dead22019-07-11 16:46:16 +0200180 goto error;
Radek Krejci084289f2019-07-09 17:35:30 +0200181 }
182
183error:
184 return ret;
185}
186
187API LY_ERR
188lys_value_validate(struct ly_ctx *ctx, const struct lysc_node *node, const char *value, size_t value_len,
189 ly_clb_resolve_prefix get_prefix, void *get_prefix_data, LYD_FORMAT format)
190{
191 LY_ERR rc = LY_SUCCESS;
192 struct ly_err_item *err = NULL;
193 struct lysc_type *type;
Radek Krejci084289f2019-07-09 17:35:30 +0200194
195 LY_CHECK_ARG_RET(ctx, node, value, LY_EINVAL);
196
197 if (!(node->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
198 LOGARG(ctx, node);
199 return LY_EINVAL;
200 }
201
202 type = ((struct lysc_node_leaf*)node)->type;
Radek Krejci73dead22019-07-11 16:46:16 +0200203 /* just validate, no storing of enything */
204 rc = type->plugin->store(ctx ? ctx : node->module->ctx, type, value, value_len, LY_TYPE_OPTS_INCOMPLETE_DATA,
205 get_prefix, get_prefix_data, format, node, NULL, NULL, NULL, &err);
206 if (rc == LY_EINCOMPLETE) {
207 /* actually success since we do not provide the context tree and call validation with
208 * LY_TYPE_OPTS_INCOMPLETE_DATA */
209 rc = LY_SUCCESS;
210 } else if (rc && err) {
211 if (ctx) {
212 /* log only in case the ctx was provided as input parameter */
213 ly_err_print(err);
214 LOGVAL(ctx, LY_VLOG_STR, err->path, err->vecode, err->msg);
Radek Krejci084289f2019-07-09 17:35:30 +0200215 }
Radek Krejci73dead22019-07-11 16:46:16 +0200216 ly_err_free(err);
Radek Krejci084289f2019-07-09 17:35:30 +0200217 }
218
219 return rc;
220}
221
222API LY_ERR
223lyd_value_validate(struct ly_ctx *ctx, const struct lyd_node_term *node, const char *value, size_t value_len,
Radek Krejci576b23f2019-07-12 14:06:32 +0200224 ly_clb_resolve_prefix get_prefix, void *get_prefix_data, LYD_FORMAT format, const struct lyd_node **trees)
Radek Krejci084289f2019-07-09 17:35:30 +0200225{
226 LY_ERR rc;
227 struct ly_err_item *err = NULL;
228 struct lysc_type *type;
Radek Krejci73dead22019-07-11 16:46:16 +0200229 int options = (trees ? 0 : LY_TYPE_OPTS_INCOMPLETE_DATA);
Radek Krejci084289f2019-07-09 17:35:30 +0200230
231 LY_CHECK_ARG_RET(ctx, node, value, LY_EINVAL);
232
233 type = ((struct lysc_node_leaf*)node->schema)->type;
Radek Krejci73dead22019-07-11 16:46:16 +0200234 rc = type->plugin->store(ctx ? ctx : node->schema->module->ctx, type, value, value_len, options,
235 get_prefix, get_prefix_data, format, trees ? (void*)node : (void*)node->schema, trees,
236 NULL, NULL, &err);
237 if (rc == LY_EINCOMPLETE) {
238 return rc;
239 } else if (rc) {
240 if (err) {
241 if (ctx) {
242 ly_err_print(err);
243 LOGVAL(ctx, LY_VLOG_STR, err->path, err->vecode, err->msg);
Radek Krejci084289f2019-07-09 17:35:30 +0200244 }
Radek Krejci73dead22019-07-11 16:46:16 +0200245 ly_err_free(err);
Radek Krejci084289f2019-07-09 17:35:30 +0200246 }
Radek Krejci73dead22019-07-11 16:46:16 +0200247 return rc;
Radek Krejci084289f2019-07-09 17:35:30 +0200248 }
249
250 return LY_SUCCESS;
251}
252
253API LY_ERR
254lyd_value_compare(const struct lyd_node_term *node, const char *value, size_t value_len,
Radek Krejci576b23f2019-07-12 14:06:32 +0200255 ly_clb_resolve_prefix get_prefix, void *get_prefix_data, LYD_FORMAT format, const struct lyd_node **trees)
Radek Krejci084289f2019-07-09 17:35:30 +0200256{
257 LY_ERR ret = LY_SUCCESS, rc;
258 struct ly_err_item *err = NULL;
259 struct ly_ctx *ctx;
260 struct lysc_type *type;
Radek Krejci084289f2019-07-09 17:35:30 +0200261 struct lyd_value data = {0};
Radek Krejci73dead22019-07-11 16:46:16 +0200262 int options = LY_TYPE_OPTS_STORE | (trees ? 0 : LY_TYPE_OPTS_INCOMPLETE_DATA);
Radek Krejci084289f2019-07-09 17:35:30 +0200263
264 LY_CHECK_ARG_RET(node ? node->schema->module->ctx : NULL, node, value, LY_EINVAL);
265
266 ctx = node->schema->module->ctx;
267 type = ((struct lysc_node_leaf*)node->schema)->type;
Radek Krejci73dead22019-07-11 16:46:16 +0200268 rc = type->plugin->store(ctx, type, value, value_len, options, get_prefix, get_prefix_data, format, (struct lyd_node*)node,
269 trees, &data, NULL, &err);
270 if (rc == LY_EINCOMPLETE) {
271 ret = rc;
272 /* continue with comparing, just remember what to return if storing is ok */
273 } else if (rc) {
274 /* value to compare is invalid */
275 ret = LY_EINVAL;
276 if (err) {
277 ly_err_free(err);
Radek Krejci084289f2019-07-09 17:35:30 +0200278 }
Radek Krejci73dead22019-07-11 16:46:16 +0200279 goto cleanup;
Radek Krejci084289f2019-07-09 17:35:30 +0200280 }
281
282 /* compare data */
Radek Krejci5af04842019-07-12 11:32:07 +0200283 if (type->plugin->compare(&node->value, &data)) {
284 /* do not assign it directly from the compare callback to keep possible LY_EINCOMPLETE from validation */
285 ret = LY_EVALID;
286 }
Radek Krejci084289f2019-07-09 17:35:30 +0200287
288cleanup:
Radek Krejci73dead22019-07-11 16:46:16 +0200289 type->plugin->free(ctx, type, &data);
Radek Krejci084289f2019-07-09 17:35:30 +0200290
291 return ret;
292}
293
Radek Krejcie7b95092019-05-15 11:03:07 +0200294static struct lyd_node *
295lyd_parse_mem_(struct ly_ctx *ctx, const char *data, LYD_FORMAT format, int options, va_list ap)
296{
Radek Krejcie7b95092019-05-15 11:03:07 +0200297 struct lyd_node *result = NULL;
298 const struct lyd_node *rpc_act = NULL, *data_tree = NULL, *iter;
Radek Krejcie92210c2019-05-17 15:53:35 +0200299#if 0
Radek Krejcie7b95092019-05-15 11:03:07 +0200300 const char *yang_data_name = NULL;
Radek Krejcie92210c2019-05-17 15:53:35 +0200301#endif
Radek Krejcie7b95092019-05-15 11:03:07 +0200302
303 if (lyd_parse_check_options(ctx, options, __func__)) {
304 return NULL;
305 }
306
307 if (options & LYD_OPT_RPCREPLY) {
308 rpc_act = va_arg(ap, const struct lyd_node *);
309 if (!rpc_act || rpc_act->parent || !(rpc_act->schema->nodetype & (LYS_ACTION | LYS_LIST | LYS_CONTAINER))) {
310 LOGERR(ctx, LY_EINVAL, "Data parser invalid variable parameter (const struct lyd_node *rpc_act).");
311 return NULL;
312 }
313 }
314 if (options & (LYD_OPT_RPC | LYD_OPT_NOTIF | LYD_OPT_RPCREPLY)) {
315 data_tree = va_arg(ap, const struct lyd_node *);
316 if (data_tree) {
317 if (options & LYD_OPT_NOEXTDEPS) {
318 LOGERR(ctx, LY_EINVAL, "%s: invalid parameter (variable arg const struct lyd_node *data_tree and LYD_OPT_NOEXTDEPS set).",
319 __func__);
320 return NULL;
321 }
322
323 LY_LIST_FOR(data_tree, iter) {
324 if (iter->parent) {
325 /* a sibling is not top-level */
326 LOGERR(ctx, LY_EINVAL, "%s: invalid variable parameter (const struct lyd_node *data_tree).", __func__);
327 return NULL;
328 }
329 }
330
331 /* move it to the beginning */
332 for (; data_tree->prev->next; data_tree = data_tree->prev);
333
334 /* LYD_OPT_NOSIBLINGS cannot be set in this case */
335 if (options & LYD_OPT_NOSIBLINGS) {
336 LOGERR(ctx, LY_EINVAL, "%s: invalid parameter (variable arg const struct lyd_node *data_tree with LYD_OPT_NOSIBLINGS).", __func__);
337 return NULL;
338 }
339 }
340 }
Radek Krejcie92210c2019-05-17 15:53:35 +0200341#if 0
Radek Krejcie7b95092019-05-15 11:03:07 +0200342 if (options & LYD_OPT_DATA_TEMPLATE) {
343 yang_data_name = va_arg(ap, const char *);
344 }
Radek Krejcie92210c2019-05-17 15:53:35 +0200345#endif
Radek Krejcie7b95092019-05-15 11:03:07 +0200346
347 if (!format) {
348 /* TODO try to detect format from the content */
349 }
350
351 switch (format) {
352 case LYD_XML:
Radek Krejcie92210c2019-05-17 15:53:35 +0200353 lyd_parse_xml(ctx, data, options, &result);
Radek Krejcie7b95092019-05-15 11:03:07 +0200354 break;
355#if 0
356 case LYD_JSON:
Radek Krejcie92210c2019-05-17 15:53:35 +0200357 lyd_parse_json(ctx, data, options, rpc_act, data_tree, yang_data_name);
Radek Krejcie7b95092019-05-15 11:03:07 +0200358 break;
359 case LYD_LYB:
Radek Krejcie92210c2019-05-17 15:53:35 +0200360 lyd_parse_lyb(ctx, data, options, data_tree, yang_data_name, NULL);
Radek Krejcie7b95092019-05-15 11:03:07 +0200361 break;
362#endif
363 case LYD_UNKNOWN:
364 LOGINT(ctx);
365 break;
366 }
367
Radek Krejcie7b95092019-05-15 11:03:07 +0200368 return result;
369}
370
371API struct lyd_node *
372lyd_parse_mem(struct ly_ctx *ctx, const char *data, LYD_FORMAT format, int options, ...)
373{
374 va_list ap;
375 struct lyd_node *result;
376
377 va_start(ap, options);
378 result = lyd_parse_mem_(ctx, data, format, options, ap);
379 va_end(ap);
380
381 return result;
382}
383
384static struct lyd_node *
385lyd_parse_fd_(struct ly_ctx *ctx, int fd, LYD_FORMAT format, int options, va_list ap)
386{
387 struct lyd_node *result;
388 size_t length;
389 char *addr;
390
391 LY_CHECK_ARG_RET(ctx, ctx, NULL);
392 if (fd < 0) {
393 LOGARG(ctx, fd);
394 return NULL;
395 }
396
397 LY_CHECK_RET(ly_mmap(ctx, fd, &length, (void **)&addr), NULL);
398 result = lyd_parse_mem_(ctx, addr ? addr : "", format, options, ap);
Radek Krejcidf3da792019-05-17 10:32:24 +0200399 if (addr) {
400 ly_munmap(addr, length);
401 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200402
403 return result;
404}
405
406API struct lyd_node *
407lyd_parse_fd(struct ly_ctx *ctx, int fd, LYD_FORMAT format, int options, ...)
408{
409 struct lyd_node *ret;
410 va_list ap;
411
412 va_start(ap, options);
413 ret = lyd_parse_fd_(ctx, fd, format, options, ap);
414 va_end(ap);
415
416 return ret;
417}
418
419API struct lyd_node *
420lyd_parse_path(struct ly_ctx *ctx, const char *path, LYD_FORMAT format, int options, ...)
421{
422 int fd;
423 struct lyd_node *result;
424 size_t len;
425 va_list ap;
426
427 LY_CHECK_ARG_RET(ctx, ctx, path, NULL);
428
429 fd = open(path, O_RDONLY);
430 LY_CHECK_ERR_RET(fd == -1, LOGERR(ctx, LY_ESYS, "Opening file \"%s\" failed (%s).", path, strerror(errno)), NULL);
431
432 if (!format) {
433 /* unknown format - try to detect it from filename's suffix */
434 len = strlen(path);
435
436 /* ignore trailing whitespaces */
437 for (; len > 0 && isspace(path[len - 1]); len--);
438
439 if (len >= 5 && !strncmp(&path[len - 4], ".xml", 4)) {
440 format = LYD_XML;
441#if 0
442 } else if (len >= 6 && !strncmp(&path[len - 5], ".json", 5)) {
443 format = LYD_JSON;
444 } else if (len >= 5 && !strncmp(&path[len - 4], ".lyb", 4)) {
445 format = LYD_LYB;
446#endif
447 } /* else still unknown, try later to detect it from the content */
448 }
449
450 va_start(ap, options);
451 result = lyd_parse_fd_(ctx, fd, format, options, ap);
452
453 va_end(ap);
454 close(fd);
455
456 return result;
457}
Radek Krejci084289f2019-07-09 17:35:30 +0200458
459API const struct lyd_node_term *
Radek Krejci576b23f2019-07-12 14:06:32 +0200460lyd_target(struct lyd_value_path *path, const struct lyd_node **trees)
Radek Krejci084289f2019-07-09 17:35:30 +0200461{
462 unsigned int u, v, x;
463 const struct lyd_node *node = NULL, *parent = NULL, *start_search;
464 uint64_t pos = 1;
465
466 LY_CHECK_ARG_RET(NULL, path, trees, NULL);
467
468 LY_ARRAY_FOR(path, u) {
469 if (parent) {
470 start_search = lyd_node_children(parent);
471search_inner:
472 node = lyd_search(start_search, path[u].node->module, path[u].node->name, strlen(path[u].node->name), path[u].node->nodetype, NULL, 0);
473 } else {
474 LY_ARRAY_FOR(trees, v) {
475 start_search = trees[v];
476search_toplevel:
477 /* WARNING! to use search_toplevel label correctly, variable v must be preserved and not changed! */
478 node = lyd_search(start_search, path[u].node->module, path[u].node->name, strlen(path[u].node->name), path[u].node->nodetype, NULL, 0);
479 if (node) {
480 break;
481 }
482 }
483 }
484 if (!node) {
485 return NULL;
486 }
487
488 /* check predicate if any */
489 LY_ARRAY_FOR(path[u].predicates, x) {
490 if (path[u].predicates[x].type == 0) {
491 /* position predicate */
492 if (pos != path[u].predicates[x].position) {
493 pos++;
494 goto search_repeat;
495 }
496 /* done, no more predicates are allowed here */
497 break;
498 } else if (path[u].predicates[x].type == 1) {
499 /* key-predicate */
500 struct lysc_type *type = ((struct lysc_node_leaf*)path[u].predicates[x].key)->type;
501 const struct lyd_node *key = lyd_search(lyd_node_children(node), path[u].predicates[x].key->module,
502 path[u].predicates[x].key->name, strlen(path[u].predicates[x].key->name),
503 LYS_LEAF, NULL, 0);
504 if (!key) {
505 /* probably error and we shouldn't be here due to previous checks when creating path */
506 goto search_repeat;
507 }
508 if (type->plugin->compare(&((struct lyd_node_term*)key)->value, path[u].predicates[x].value)) {
509 goto search_repeat;
510 }
511 } else if (path[u].predicates[x].type == 2) {
512 /* leaf-list-predicate */
513 struct lysc_type *type = ((struct lysc_node_leaf*)path[u].node)->type;
514 if (type->plugin->compare(&((struct lyd_node_term*)node)->value, path[u].predicates[x].value)) {
515 goto search_repeat;
516 }
517 } else {
518 LOGINT(NULL);
519 }
520 }
521
522 parent = node;
523 }
524
525 return (const struct lyd_node_term*)node;
526
527search_repeat:
528 start_search = node->next;
529 if (parent) {
530 goto search_inner;
531 } else {
532 goto search_toplevel;
533 }
534}
535
536