blob: f38ea93c7b9ff1bf17ff5ba9a02c07833dd99787 [file] [log] [blame]
Radek Krejci3f5e3db2018-10-11 15:57:47 +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 */
Radek Krejcib7db73a2018-10-24 14:18:40 +020014
Radek Krejci535ea9f2020-05-29 16:01:05 +020015#define _GNU_SOURCE
16
Radek Krejcica376bd2020-06-11 16:04:06 +020017#include "tree_schema.h"
Radek Krejci86d106e2018-10-18 09:53:19 +020018
Radek Krejcie7b95092019-05-15 11:03:07 +020019#include <assert.h>
Radek Krejcid33273d2018-10-25 14:55:52 +020020#include <dirent.h>
Radek Krejci86d106e2018-10-18 09:53:19 +020021#include <errno.h>
Radek Krejcie7b95092019-05-15 11:03:07 +020022#include <stdint.h>
Radek Krejci86d106e2018-10-18 09:53:19 +020023#include <stdio.h>
Radek Krejcie7b95092019-05-15 11:03:07 +020024#include <stdlib.h>
25#include <string.h>
Radek Krejci86d106e2018-10-18 09:53:19 +020026#include <sys/stat.h>
Radek Krejci86d106e2018-10-18 09:53:19 +020027#include <unistd.h>
Radek Krejci3f5e3db2018-10-11 15:57:47 +020028
Radek Krejcica376bd2020-06-11 16:04:06 +020029#include "common.h"
Michal Vasko5aa44c02020-06-29 11:47:02 +020030#include "compat.h"
Radek Krejci86d106e2018-10-18 09:53:19 +020031#include "context.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020032#include "dict.h"
33#include "log.h"
Michal Vaskoafac7822020-10-20 14:22:26 +020034#include "in_internal.h"
Radek Krejcif0e1ba52020-05-22 15:14:35 +020035#include "parser_internal.h"
Radek Krejcica376bd2020-06-11 16:04:06 +020036#include "parser_schema.h"
Michal Vasko40308e72020-10-20 16:38:40 +020037#include "path.h"
Michal Vasko1a7a7bd2020-10-16 14:39:15 +020038#include "schema_compile.h"
39#include "schema_compile_amend.h"
Radek Krejcica376bd2020-06-11 16:04:06 +020040#include "set.h"
41#include "tree.h"
42#include "tree_schema_internal.h"
43#include "xpath.h"
Radek Krejci3f5e3db2018-10-11 15:57:47 +020044
Michal Vaskof1ab44f2020-10-22 08:58:32 +020045API LY_ERR
46lysc_tree_dfs_full(const struct lysc_node *root, lysc_dfs_clb dfs_clb, void *data)
47{
48 struct lysc_node *elem, *ops, *elem2;
49 LY_ARRAY_COUNT_TYPE u;
50
51 LY_CHECK_ARG_RET(NULL, root, dfs_clb, LY_EINVAL);
52
53 LYSC_TREE_DFS_BEGIN(root, elem) {
54 /* schema node */
55 LY_CHECK_RET(dfs_clb(elem, data, &LYSC_TREE_DFS_continue));
56
57 ops = (struct lysc_node *)lysc_node_actions(elem);
58 LY_ARRAY_FOR(ops, u) {
59 LYSC_TREE_DFS_BEGIN(&ops[u], elem2) {
60 /* action subtree */
61 LY_CHECK_RET(dfs_clb(elem2, data, &LYSC_TREE_DFS_continue));
62
63 LYSC_TREE_DFS_END(&ops[u], elem2);
64 }
65 }
66
67 ops = (struct lysc_node *)lysc_node_notifs(elem);
68 LY_ARRAY_FOR(ops, u) {
69 LYSC_TREE_DFS_BEGIN(&ops[u], elem2) {
70 /* notification subtree */
71 LY_CHECK_RET(dfs_clb(elem2, data, &LYSC_TREE_DFS_continue));
72
73 LYSC_TREE_DFS_END(&ops[u], elem2);
74 }
75 }
76
77 LYSC_TREE_DFS_END(root, elem);
78 }
79
80 return LY_SUCCESS;
81}
82
83API LY_ERR
84lysc_module_dfs_full(const struct lys_module *mod, lysc_dfs_clb dfs_clb, void *data)
85{
86 LY_ARRAY_COUNT_TYPE u;
87
88 LY_CHECK_ARG_RET(NULL, mod, mod->compiled, dfs_clb, LY_EINVAL);
89
90 /* schema nodes */
91 LY_CHECK_RET(lysc_tree_dfs_full(mod->compiled->data, dfs_clb, data));
92
93 /* RPCs */
94 LY_ARRAY_FOR(mod->compiled->rpcs, u) {
95 LY_CHECK_RET(lysc_tree_dfs_full((struct lysc_node *)&mod->compiled->rpcs[u], dfs_clb, data));
96 }
97
98 /* notifications */
99 LY_ARRAY_FOR(mod->compiled->notifs, u) {
100 LY_CHECK_RET(lysc_tree_dfs_full((struct lysc_node *)&mod->compiled->notifs[u], dfs_clb, data));
101 }
102
103 return LY_SUCCESS;
104}
105
Radek Krejcia3045382018-11-22 14:30:31 +0100106API const struct lysc_node *
Radek Krejci1deb5be2020-08-26 16:43:36 +0200107lys_getnext(const struct lysc_node *last, const struct lysc_node *parent, const struct lysc_module *module, uint32_t options)
Radek Krejcia3045382018-11-22 14:30:31 +0100108{
Radek Krejci6eeb58f2019-02-22 16:29:37 +0100109 const struct lysc_node *next = NULL;
Radek Krejcia3045382018-11-22 14:30:31 +0100110 struct lysc_node **snode;
Radek Krejci857189e2020-09-01 13:26:36 +0200111 ly_bool action_flag = 0, notif_flag = 0;
Radek Krejci6eeb58f2019-02-22 16:29:37 +0100112 const struct lysc_action *actions;
113 const struct lysc_notif *notifs;
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200114 LY_ARRAY_COUNT_TYPE u;
Radek Krejcia3045382018-11-22 14:30:31 +0100115
116 LY_CHECK_ARG_RET(NULL, parent || module, NULL);
117
Radek Krejcid5a2b9d2019-04-12 10:39:30 +0200118next:
Radek Krejcia3045382018-11-22 14:30:31 +0100119 if (!last) {
120 /* first call */
121
122 /* get know where to start */
123 if (parent) {
124 /* schema subtree */
Michal Vasko69730152020-10-09 16:30:07 +0200125 if ((parent->nodetype == LYS_CHOICE) && (options & LYS_GETNEXT_WITHCASE)) {
Michal Vasko22df3f02020-08-24 13:29:22 +0200126 if (((struct lysc_node_choice *)parent)->cases) {
127 next = last = (const struct lysc_node *)&((struct lysc_node_choice *)parent)->cases[0];
Radek Krejci056d0a82018-12-06 16:57:25 +0100128 }
Radek Krejci056d0a82018-12-06 16:57:25 +0100129 } else {
Radek Krejci6eeb58f2019-02-22 16:29:37 +0100130 snode = lysc_node_children_p(parent, (options & LYS_GETNEXT_OUTPUT) ? LYS_CONFIG_R : LYS_CONFIG_W);
Radek Krejci05b774b2019-02-25 13:26:18 +0100131 /* do not return anything if the node does not have any children */
Radek Krejcid5a2b9d2019-04-12 10:39:30 +0200132 if (snode && *snode) {
133 next = last = *snode;
Radek Krejci056d0a82018-12-06 16:57:25 +0100134 }
Radek Krejcia3045382018-11-22 14:30:31 +0100135 }
Radek Krejcia3045382018-11-22 14:30:31 +0100136 } else {
137 /* top level data */
138 next = last = module->data;
139 }
140 if (!next) {
Radek Krejci6eeb58f2019-02-22 16:29:37 +0100141 /* try to get action or notification */
142 goto repeat;
Radek Krejcia3045382018-11-22 14:30:31 +0100143 }
Radek Krejci05b774b2019-02-25 13:26:18 +0100144 /* test if the next can be returned */
145 goto check;
146
Michal Vasko1bf09392020-03-27 12:38:10 +0100147 } else if (last->nodetype & (LYS_RPC | LYS_ACTION)) {
Radek Krejci05b774b2019-02-25 13:26:18 +0100148 action_flag = 1;
Radek Krejci6eeb58f2019-02-22 16:29:37 +0100149 if (last->parent) {
150 actions = lysc_node_actions(last->parent);
151 } else {
152 actions = module->rpcs;
153 }
154 LY_ARRAY_FOR(actions, u) {
Michal Vasko22df3f02020-08-24 13:29:22 +0200155 if (&actions[u] == (struct lysc_action *)last) {
Radek Krejci6eeb58f2019-02-22 16:29:37 +0100156 break;
157 }
158 }
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200159 if (u + 1 < LY_ARRAY_COUNT(actions)) {
Michal Vasko22df3f02020-08-24 13:29:22 +0200160 next = (struct lysc_node *)(&actions[u + 1]);
Radek Krejci6eeb58f2019-02-22 16:29:37 +0100161 }
162 goto repeat;
163 } else if (last->nodetype == LYS_NOTIF) {
Radek Krejci05b774b2019-02-25 13:26:18 +0100164 action_flag = notif_flag = 1;
Radek Krejci6eeb58f2019-02-22 16:29:37 +0100165 if (last->parent) {
166 notifs = lysc_node_notifs(last->parent);
167 } else {
168 notifs = module->notifs;
169 }
170 LY_ARRAY_FOR(notifs, u) {
Michal Vasko22df3f02020-08-24 13:29:22 +0200171 if (&notifs[u] == (struct lysc_notif *)last) {
Radek Krejci6eeb58f2019-02-22 16:29:37 +0100172 break;
173 }
174 }
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200175 if (u + 1 < LY_ARRAY_COUNT(notifs)) {
Michal Vasko22df3f02020-08-24 13:29:22 +0200176 next = (struct lysc_node *)(&notifs[u + 1]);
Radek Krejci6eeb58f2019-02-22 16:29:37 +0100177 }
178 goto repeat;
Michal Vasko20424b42020-08-31 12:29:38 +0200179 } else {
180 next = last->next;
Radek Krejcia3045382018-11-22 14:30:31 +0100181 }
182
Radek Krejcia3045382018-11-22 14:30:31 +0100183repeat:
184 if (!next) {
Radek Krejcia9026eb2018-12-12 16:04:47 +0100185 /* possibly go back to parent */
Michal Vasko69730152020-10-09 16:30:07 +0200186 if (last && (last->parent != parent)) {
Radek Krejcia9026eb2018-12-12 16:04:47 +0100187 last = last->parent;
Radek Krejcid5a2b9d2019-04-12 10:39:30 +0200188 goto next;
Radek Krejci6eeb58f2019-02-22 16:29:37 +0100189 } else if (!action_flag) {
190 action_flag = 1;
Michal Vasko22df3f02020-08-24 13:29:22 +0200191 next = parent ? (struct lysc_node *)lysc_node_actions(parent) : (struct lysc_node *)module->rpcs;
Radek Krejci6eeb58f2019-02-22 16:29:37 +0100192 } else if (!notif_flag) {
193 notif_flag = 1;
Michal Vasko22df3f02020-08-24 13:29:22 +0200194 next = parent ? (struct lysc_node *)lysc_node_notifs(parent) : (struct lysc_node *)module->notifs;
Radek Krejci6eeb58f2019-02-22 16:29:37 +0100195 } else {
196 return NULL;
Radek Krejcia9026eb2018-12-12 16:04:47 +0100197 }
Radek Krejci6eeb58f2019-02-22 16:29:37 +0100198 goto repeat;
Radek Krejcia3045382018-11-22 14:30:31 +0100199 }
Radek Krejci05b774b2019-02-25 13:26:18 +0100200check:
Radek Krejcia3045382018-11-22 14:30:31 +0100201 switch (next->nodetype) {
Michal Vasko1bf09392020-03-27 12:38:10 +0100202 case LYS_RPC:
Radek Krejcia3045382018-11-22 14:30:31 +0100203 case LYS_ACTION:
204 case LYS_NOTIF:
205 case LYS_LEAF:
206 case LYS_ANYXML:
207 case LYS_ANYDATA:
208 case LYS_LIST:
209 case LYS_LEAFLIST:
210 break;
Michal Vasko20424b42020-08-31 12:29:38 +0200211 case LYS_CASE:
212 if (options & LYS_GETNEXT_WITHCASE) {
213 break;
214 } else {
215 /* go into */
216 next = ((struct lysc_node_case *)next)->child;
217 }
218 goto repeat;
Radek Krejcia3045382018-11-22 14:30:31 +0100219 case LYS_CONTAINER:
220 if (!(((struct lysc_node_container *)next)->flags & LYS_PRESENCE) && (options & LYS_GETNEXT_INTONPCONT)) {
221 if (((struct lysc_node_container *)next)->child) {
222 /* go into */
223 next = ((struct lysc_node_container *)next)->child;
224 } else {
225 next = next->next;
226 }
227 goto repeat;
228 }
229 break;
230 case LYS_CHOICE:
231 if (options & LYS_GETNEXT_WITHCHOICE) {
Michal Vasko20424b42020-08-31 12:29:38 +0200232 break;
Radek Krejci9bb94eb2018-12-04 16:48:35 +0100233 } else if ((options & LYS_GETNEXT_NOCHOICE) || !((struct lysc_node_choice *)next)->cases) {
234 next = next->next;
235 } else {
Radek Krejcia3045382018-11-22 14:30:31 +0100236 /* go into */
Radek Krejcia9026eb2018-12-12 16:04:47 +0100237 if (options & LYS_GETNEXT_WITHCASE) {
Michal Vasko22df3f02020-08-24 13:29:22 +0200238 next = (struct lysc_node *)((struct lysc_node_choice *)next)->cases;
Radek Krejcia9026eb2018-12-12 16:04:47 +0100239 } else {
Radek Krejciff2dbc52020-11-02 11:05:09 +0100240 const struct lysc_node_case *cs = NULL;
241 for (cs = ((struct lysc_node_choice *)next)->cases; cs; cs = (const struct lysc_node_case*)cs->next) {
242 if (cs->child) {
243 /* there is something to return */
244 next = cs->child;
245 break;
246 }
247 }
248 if (!cs) {
249 /* no children in choice's cases, so go to the choice's sibling instead of into it */
250 next = next->next;
251 }
Radek Krejcia9026eb2018-12-12 16:04:47 +0100252 }
Radek Krejcia3045382018-11-22 14:30:31 +0100253 }
254 goto repeat;
255 default:
256 /* we should not be here */
Radek Krejcib07b5c92019-04-08 10:56:37 +0200257 LOGINT(module ? module->mod->ctx : parent->module->ctx);
Radek Krejcia3045382018-11-22 14:30:31 +0100258 return NULL;
259 }
260
261 if (!(options & LYS_GETNEXT_NOSTATECHECK)) {
262 /* check if the node is disabled by if-feature */
Radek Krejcifab954b2019-09-11 11:25:14 +0200263 if (lysc_node_is_disabled(next, 0)) {
Radek Krejcia3045382018-11-22 14:30:31 +0100264 next = next->next;
265 goto repeat;
266 }
267 }
268 return next;
269}
270
271API const struct lysc_node *
Michal Vaskoe444f752020-02-10 12:20:06 +0100272lys_find_child(const struct lysc_node *parent, const struct lys_module *module, const char *name, size_t name_len,
Radek Krejci1deb5be2020-08-26 16:43:36 +0200273 uint16_t nodetype, uint32_t options)
Radek Krejcia3045382018-11-22 14:30:31 +0100274{
275 const struct lysc_node *node = NULL;
276
277 LY_CHECK_ARG_RET(NULL, module, name, NULL);
278 if (!nodetype) {
279 nodetype = 0xffff;
280 }
281
282 while ((node = lys_getnext(node, parent, module->compiled, options))) {
283 if (!(node->nodetype & nodetype)) {
284 continue;
285 }
286 if (node->module != module) {
287 continue;
288 }
289
290 if (name_len) {
Radek Krejci7f9b6512019-09-18 13:11:09 +0200291 if (!ly_strncmp(node->name, name, name_len)) {
Radek Krejcia3045382018-11-22 14:30:31 +0100292 return node;
293 }
294 } else {
295 if (!strcmp(node->name, name)) {
296 return node;
297 }
298 }
299 }
300 return NULL;
301}
302
Michal Vasko519fd602020-05-26 12:17:39 +0200303API LY_ERR
Radek Krejcibed13942020-10-19 16:06:28 +0200304lys_find_xpath_atoms(const struct lysc_node *ctx_node, const char *xpath, uint32_t options, struct ly_set **set)
Michal Vasko519fd602020-05-26 12:17:39 +0200305{
306 LY_ERR ret = LY_SUCCESS;
307 struct lyxp_set xp_set;
Radek Krejcif03a9e22020-09-18 20:09:31 +0200308 struct lyxp_expr *exp = NULL;
Michal Vasko519fd602020-05-26 12:17:39 +0200309 uint32_t i;
310
311 LY_CHECK_ARG_RET(NULL, ctx_node, xpath, set, LY_EINVAL);
312 if (!(options & LYXP_SCNODE_ALL)) {
313 options = LYXP_SCNODE;
314 }
315
316 memset(&xp_set, 0, sizeof xp_set);
317
318 /* compile expression */
Radek Krejcif03a9e22020-09-18 20:09:31 +0200319 ret = lyxp_expr_parse(ctx_node->module->ctx, xpath, 0, 1, &exp);
320 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko519fd602020-05-26 12:17:39 +0200321
322 /* atomize expression */
Michal Vasko5d24f6c2020-10-13 13:49:06 +0200323 ret = lyxp_atomize(exp, NULL, LY_PREF_JSON, NULL, ctx_node, &xp_set, options);
Michal Vasko519fd602020-05-26 12:17:39 +0200324 LY_CHECK_GOTO(ret, cleanup);
325
326 /* allocate return set */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200327 ret = ly_set_new(set);
328 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko519fd602020-05-26 12:17:39 +0200329
330 /* transform into ly_set */
331 (*set)->objs = malloc(xp_set.used * sizeof *(*set)->objs);
332 LY_CHECK_ERR_GOTO(!(*set)->objs, LOGMEM(ctx_node->module->ctx); ret = LY_EMEM, cleanup);
333 (*set)->size = xp_set.used;
334
335 for (i = 0; i < xp_set.used; ++i) {
Michal Vasko004d3152020-06-11 19:59:22 +0200336 if (xp_set.val.scnodes[i].type == LYXP_NODE_ELEM) {
Radek Krejci3d92e442020-10-12 12:48:13 +0200337 ret = ly_set_add(*set, xp_set.val.scnodes[i].scnode, 1, NULL);
Radek Krejciba03a5a2020-08-27 14:40:41 +0200338 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko519fd602020-05-26 12:17:39 +0200339 }
340 }
341
342cleanup:
343 lyxp_set_free_content(&xp_set);
344 lyxp_expr_free(ctx_node->module->ctx, exp);
345 return ret;
346}
347
Michal Vasko072de482020-08-05 13:27:21 +0200348API LY_ERR
Michal Vasko40308e72020-10-20 16:38:40 +0200349lys_find_path_atoms(const struct ly_path *path, struct ly_set **set)
350{
351 LY_ERR ret = LY_SUCCESS;
352 LY_ARRAY_COUNT_TYPE u, v;
353
354 LY_CHECK_ARG_RET(NULL, path, set, LY_EINVAL);
355
356 /* allocate return set */
357 LY_CHECK_RET(ly_set_new(set));
358
359 LY_ARRAY_FOR(path, u) {
360 /* add nodes from the path */
361 LY_CHECK_GOTO(ret = ly_set_add(*set, (void *)path[u].node, 0, NULL), cleanup);
362 if (path[u].pred_type == LY_PATH_PREDTYPE_LIST) {
363 LY_ARRAY_FOR(path[u].predicates, v) {
364 /* add all the keys in a predicate */
365 LY_CHECK_GOTO(ret = ly_set_add(*set, (void *)path[u].predicates[v].key, 0, NULL), cleanup);
366 }
367 }
368 }
369
370cleanup:
371 if (ret) {
372 ly_set_free(*set, NULL);
373 *set = NULL;
374 }
375 return ret;
376}
377
378API LY_ERR
379lys_find_expr_atoms(const struct lysc_node *ctx_node, const struct lys_module *cur_mod, const struct lyxp_expr *expr,
380 const struct lysc_prefix *prefixes, uint32_t options, struct ly_set **set)
381{
382 LY_ERR ret = LY_SUCCESS;
383 struct lyxp_set xp_set = {0};
384 uint32_t i;
385
386 LY_CHECK_ARG_RET(NULL, cur_mod, expr, prefixes, set, LY_EINVAL);
387 if (!(options & LYXP_SCNODE_ALL)) {
388 options = LYXP_SCNODE;
389 }
390
391 /* atomize expression */
392 ret = lyxp_atomize(expr, cur_mod, LY_PREF_SCHEMA_RESOLVED, (void *)prefixes, ctx_node, &xp_set, options);
393 LY_CHECK_GOTO(ret, cleanup);
394
395 /* allocate return set */
396 ret = ly_set_new(set);
397 LY_CHECK_GOTO(ret, cleanup);
398
399 /* transform into ly_set */
400 (*set)->objs = malloc(xp_set.used * sizeof *(*set)->objs);
401 LY_CHECK_ERR_GOTO(!(*set)->objs, LOGMEM(cur_mod->ctx); ret = LY_EMEM, cleanup);
402 (*set)->size = xp_set.used;
403
404 for (i = 0; i < xp_set.used; ++i) {
405 if ((xp_set.val.scnodes[i].type == LYXP_NODE_ELEM) && (xp_set.val.scnodes[i].in_ctx == 1)) {
406 ret = ly_set_add(*set, xp_set.val.scnodes[i].scnode, 1, NULL);
407 LY_CHECK_GOTO(ret, cleanup);
408 }
409 }
410
411cleanup:
412 lyxp_set_free_content(&xp_set);
413 if (ret) {
414 ly_set_free(*set, NULL);
415 *set = NULL;
416 }
417 return ret;
418}
419
420API LY_ERR
Radek Krejci1deb5be2020-08-26 16:43:36 +0200421lys_find_xpath(const struct lysc_node *ctx_node, const char *xpath, uint32_t options, struct ly_set **set)
Michal Vasko072de482020-08-05 13:27:21 +0200422{
423 LY_ERR ret = LY_SUCCESS;
Michal Vasko40308e72020-10-20 16:38:40 +0200424 struct lyxp_set xp_set = {0};
Radek Krejcif03a9e22020-09-18 20:09:31 +0200425 struct lyxp_expr *exp = NULL;
Michal Vasko072de482020-08-05 13:27:21 +0200426 uint32_t i;
427
428 LY_CHECK_ARG_RET(NULL, ctx_node, xpath, set, LY_EINVAL);
429 if (!(options & LYXP_SCNODE_ALL)) {
430 options = LYXP_SCNODE;
431 }
432
Michal Vasko072de482020-08-05 13:27:21 +0200433 /* compile expression */
Radek Krejcif03a9e22020-09-18 20:09:31 +0200434 ret = lyxp_expr_parse(ctx_node->module->ctx, xpath, 0, 1, &exp);
435 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko072de482020-08-05 13:27:21 +0200436
437 /* atomize expression */
Michal Vasko5d24f6c2020-10-13 13:49:06 +0200438 ret = lyxp_atomize(exp, NULL, LY_PREF_JSON, NULL, ctx_node, &xp_set, options);
Michal Vasko072de482020-08-05 13:27:21 +0200439 LY_CHECK_GOTO(ret, cleanup);
440
441 /* allocate return set */
Radek Krejciba03a5a2020-08-27 14:40:41 +0200442 ret = ly_set_new(set);
443 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko072de482020-08-05 13:27:21 +0200444
445 /* transform into ly_set */
446 (*set)->objs = malloc(xp_set.used * sizeof *(*set)->objs);
447 LY_CHECK_ERR_GOTO(!(*set)->objs, LOGMEM(ctx_node->module->ctx); ret = LY_EMEM, cleanup);
448 (*set)->size = xp_set.used;
449
450 for (i = 0; i < xp_set.used; ++i) {
451 if ((xp_set.val.scnodes[i].type == LYXP_NODE_ELEM) && (xp_set.val.scnodes[i].in_ctx == 1)) {
Radek Krejci3d92e442020-10-12 12:48:13 +0200452 ret = ly_set_add(*set, xp_set.val.scnodes[i].scnode, 1, NULL);
Radek Krejciba03a5a2020-08-27 14:40:41 +0200453 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko072de482020-08-05 13:27:21 +0200454 }
455 }
456
457cleanup:
458 lyxp_set_free_content(&xp_set);
459 lyxp_expr_free(ctx_node->module->ctx, exp);
Michal Vaskoae159662020-10-21 11:57:24 +0200460 if (ret) {
Michal Vasko40308e72020-10-20 16:38:40 +0200461 ly_set_free(*set, NULL);
462 *set = NULL;
463 }
Michal Vasko072de482020-08-05 13:27:21 +0200464 return ret;
465}
466
Michal Vasko14654712020-02-06 08:35:21 +0100467char *
468lysc_path_until(const struct lysc_node *node, const struct lysc_node *parent, LYSC_PATH_TYPE pathtype, char *buffer,
Radek Krejci0f969882020-08-21 16:56:47 +0200469 size_t buflen)
Radek Krejci327de162019-06-14 12:52:07 +0200470{
Michal Vasko03ff5a72019-09-11 13:49:33 +0200471 const struct lysc_node *iter;
Radek Krejci327de162019-06-14 12:52:07 +0200472 char *path = NULL;
473 int len = 0;
474
Radek Krejci3bbd93e2019-07-24 09:57:23 +0200475 LY_CHECK_ARG_RET(NULL, node, NULL);
476 if (buffer) {
477 LY_CHECK_ARG_RET(node->module->ctx, buflen > 1, NULL);
478 }
479
Radek Krejci327de162019-06-14 12:52:07 +0200480 switch (pathtype) {
Michal Vasko03ff5a72019-09-11 13:49:33 +0200481 case LYSC_PATH_LOG:
Michal Vasko65de0402020-08-03 16:34:19 +0200482 case LYSC_PATH_DATA:
Michal Vasko90932a92020-02-12 14:33:03 +0100483 for (iter = node; iter && (iter != parent) && (len >= 0); iter = iter->parent) {
Michal Vasko11deea12020-08-05 13:54:50 +0200484 char *s, *id;
Michal Vasko14654712020-02-06 08:35:21 +0100485 const char *slash;
Radek Krejci327de162019-06-14 12:52:07 +0200486
Michal Vasko65de0402020-08-03 16:34:19 +0200487 if ((pathtype == LYSC_PATH_DATA) && (iter->nodetype & (LYS_CHOICE | LYS_CASE))) {
488 /* schema-only node */
489 continue;
490 }
491
Michal Vasko11deea12020-08-05 13:54:50 +0200492 s = buffer ? strdup(buffer) : path;
Michal Vasko03ff5a72019-09-11 13:49:33 +0200493 id = strdup(iter->name);
Michal Vasko14654712020-02-06 08:35:21 +0100494 if (parent && (iter->parent == parent)) {
495 slash = "";
496 } else {
497 slash = "/";
498 }
Michal Vasko69730152020-10-09 16:30:07 +0200499 if (!iter->parent || (iter->parent->module != iter->module)) {
Radek Krejci327de162019-06-14 12:52:07 +0200500 /* print prefix */
Radek Krejci1c0c3442019-07-23 16:08:47 +0200501 if (buffer) {
Michal Vasko14654712020-02-06 08:35:21 +0100502 len = snprintf(buffer, buflen, "%s%s:%s%s", slash, iter->module->name, id, s ? s : "");
Radek Krejci1c0c3442019-07-23 16:08:47 +0200503 } else {
Michal Vasko14654712020-02-06 08:35:21 +0100504 len = asprintf(&path, "%s%s:%s%s", slash, iter->module->name, id, s ? s : "");
Radek Krejci1c0c3442019-07-23 16:08:47 +0200505 }
Radek Krejci327de162019-06-14 12:52:07 +0200506 } else {
507 /* prefix is the same as in parent */
Radek Krejci1c0c3442019-07-23 16:08:47 +0200508 if (buffer) {
Michal Vasko14654712020-02-06 08:35:21 +0100509 len = snprintf(buffer, buflen, "%s%s%s", slash, id, s ? s : "");
Radek Krejci1c0c3442019-07-23 16:08:47 +0200510 } else {
Michal Vasko14654712020-02-06 08:35:21 +0100511 len = asprintf(&path, "%s%s%s", slash, id, s ? s : "");
Radek Krejci1c0c3442019-07-23 16:08:47 +0200512 }
Radek Krejci327de162019-06-14 12:52:07 +0200513 }
514 free(s);
515 free(id);
Radek Krejci1c0c3442019-07-23 16:08:47 +0200516
Michal Vasko69730152020-10-09 16:30:07 +0200517 if (buffer && (buflen <= (size_t)len)) {
Radek Krejci1c0c3442019-07-23 16:08:47 +0200518 /* not enough space in buffer */
519 break;
520 }
Radek Krejci327de162019-06-14 12:52:07 +0200521 }
522
523 if (len < 0) {
524 free(path);
525 path = NULL;
526 } else if (len == 0) {
Radek Krejci3bbd93e2019-07-24 09:57:23 +0200527 if (buffer) {
528 strcpy(buffer, "/");
529 } else {
530 path = strdup("/");
531 }
Radek Krejci327de162019-06-14 12:52:07 +0200532 }
533 break;
534 }
535
Radek Krejci1c0c3442019-07-23 16:08:47 +0200536 if (buffer) {
537 return buffer;
538 } else {
539 return path;
540 }
Radek Krejci327de162019-06-14 12:52:07 +0200541}
542
Michal Vasko14654712020-02-06 08:35:21 +0100543API char *
544lysc_path(const struct lysc_node *node, LYSC_PATH_TYPE pathtype, char *buffer, size_t buflen)
545{
546 return lysc_path_until(node, NULL, pathtype, buffer, buflen);
547}
548
Michal Vasko28d78432020-05-26 13:10:53 +0200549API LY_ERR
Radek Krejci19a96102018-11-15 13:38:09 +0100550lysc_feature_value(const struct lysc_feature *feature)
Radek Krejci6f7feb62018-10-12 15:23:02 +0200551{
Michal Vasko28d78432020-05-26 13:10:53 +0200552 LY_CHECK_ARG_RET(NULL, feature, LY_EINVAL);
553 return feature->flags & LYS_FENABLED ? LY_SUCCESS : LY_ENOT;
Radek Krejci151a5b72018-10-19 14:21:44 +0200554}
555
Radek Krejci693262f2019-04-29 15:23:20 +0200556uint8_t
Radek Krejci1deb5be2020-08-26 16:43:36 +0200557lysc_iff_getop(uint8_t *list, size_t pos)
Radek Krejci151a5b72018-10-19 14:21:44 +0200558{
559 uint8_t *item;
560 uint8_t mask = 3, result;
561
Radek Krejci151a5b72018-10-19 14:21:44 +0200562 item = &list[pos / 4];
563 result = (*item) & (mask << 2 * (pos % 4));
564 return result >> 2 * (pos % 4);
565}
566
Michal Vasko28d78432020-05-26 13:10:53 +0200567static LY_ERR
Radek Krejci1deb5be2020-08-26 16:43:36 +0200568lysc_iffeature_value_(const struct lysc_iffeature *iff, size_t *index_e, size_t *index_f)
Radek Krejci151a5b72018-10-19 14:21:44 +0200569{
570 uint8_t op;
Michal Vasko28d78432020-05-26 13:10:53 +0200571 LY_ERR a, b;
Radek Krejci151a5b72018-10-19 14:21:44 +0200572
Radek Krejci693262f2019-04-29 15:23:20 +0200573 op = lysc_iff_getop(iff->expr, *index_e);
Radek Krejci151a5b72018-10-19 14:21:44 +0200574 (*index_e)++;
575
576 switch (op) {
577 case LYS_IFF_F:
578 /* resolve feature */
Radek Krejci2c4e7172018-10-19 15:56:26 +0200579 return lysc_feature_value(iff->features[(*index_f)++]);
Radek Krejci151a5b72018-10-19 14:21:44 +0200580 case LYS_IFF_NOT:
581 /* invert result */
Michal Vasko28d78432020-05-26 13:10:53 +0200582 return lysc_iffeature_value_(iff, index_e, index_f) == LY_SUCCESS ? LY_ENOT : LY_SUCCESS;
Radek Krejci151a5b72018-10-19 14:21:44 +0200583 case LYS_IFF_AND:
584 case LYS_IFF_OR:
585 a = lysc_iffeature_value_(iff, index_e, index_f);
586 b = lysc_iffeature_value_(iff, index_e, index_f);
587 if (op == LYS_IFF_AND) {
Michal Vasko28d78432020-05-26 13:10:53 +0200588 if ((a == LY_SUCCESS) && (b == LY_SUCCESS)) {
589 return LY_SUCCESS;
590 } else {
591 return LY_ENOT;
592 }
Radek Krejci151a5b72018-10-19 14:21:44 +0200593 } else { /* LYS_IFF_OR */
Michal Vasko28d78432020-05-26 13:10:53 +0200594 if ((a == LY_SUCCESS) || (b == LY_SUCCESS)) {
595 return LY_SUCCESS;
596 } else {
597 return LY_ENOT;
598 }
Radek Krejci151a5b72018-10-19 14:21:44 +0200599 }
600 }
601
602 return 0;
603}
604
Michal Vasko28d78432020-05-26 13:10:53 +0200605API LY_ERR
Radek Krejci151a5b72018-10-19 14:21:44 +0200606lysc_iffeature_value(const struct lysc_iffeature *iff)
607{
Radek Krejci1deb5be2020-08-26 16:43:36 +0200608 size_t index_e = 0, index_f = 0;
Radek Krejci151a5b72018-10-19 14:21:44 +0200609
610 LY_CHECK_ARG_RET(NULL, iff, -1);
611
612 if (iff->expr) {
613 return lysc_iffeature_value_(iff, &index_e, &index_f);
614 }
615 return 0;
616}
617
Radek Krejci151a5b72018-10-19 14:21:44 +0200618/**
619 * @brief Enable/Disable the specified feature in the module.
620 *
621 * If the feature is already set to the desired value, LY_SUCCESS is returned.
622 * By changing the feature, also all the feature which depends on it via their
Radek Krejcia8c71e62020-10-26 08:30:50 +0100623 * if-feature statements are again evaluated (disabled if a if-feature statement
Radek Krejci151a5b72018-10-19 14:21:44 +0200624 * evaluates to false).
625 *
Radek Krejci0af46292019-01-11 16:02:31 +0100626 * @param[in] mod Module where to set (search for) the feature.
Radek Krejci151a5b72018-10-19 14:21:44 +0200627 * @param[in] name Name of the feature to set. Asterisk ('*') can be used to
628 * set all the features in the module.
629 * @param[in] value Desired value of the feature: 1 (enable) or 0 (disable).
Radek Krejci857189e2020-09-01 13:26:36 +0200630 * @param[in] skip_checks Flag to skip checking of if-features and just set @p value of the feature.
Radek Krejci151a5b72018-10-19 14:21:44 +0200631 * @return LY_ERR value.
632 */
633static LY_ERR
Radek Krejci857189e2020-09-01 13:26:36 +0200634lys_feature_change(const struct lys_module *mod, const char *name, ly_bool value, ly_bool skip_checks)
Radek Krejci151a5b72018-10-19 14:21:44 +0200635{
Michal Vaskob0099a92020-08-31 14:55:23 +0200636 LY_ERR ret = LY_SUCCESS;
Radek Krejci857189e2020-09-01 13:26:36 +0200637 ly_bool all = 0;
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200638 LY_ARRAY_COUNT_TYPE u, disabled_count;
Radek Krejci7eb54ba2020-05-18 16:30:04 +0200639 uint32_t changed_count;
Radek Krejci151a5b72018-10-19 14:21:44 +0200640 struct lysc_feature *f, **df;
641 struct lysc_iffeature *iff;
642 struct ly_set *changed;
Radek Krejci0af46292019-01-11 16:02:31 +0100643 struct ly_ctx *ctx = mod->ctx; /* shortcut */
Radek Krejci151a5b72018-10-19 14:21:44 +0200644
Radek Krejci6e67c402019-05-02 09:55:39 +0200645 if (!strcmp(name, "*")) {
646 /* enable all */
647 all = 1;
648 }
649
Michal Vasko997f9822020-10-14 13:09:05 +0200650 if (!mod->implemented) {
651 LOGERR(ctx, LY_EINVAL, "Module \"%s\" is not implemented so all its features are permanently disabled.", mod->name);
Radek Krejci0af46292019-01-11 16:02:31 +0100652 return LY_EINVAL;
653 }
Radek Krejci14915cc2020-09-14 17:28:13 +0200654 if (!mod->features) {
Radek Krejci6e67c402019-05-02 09:55:39 +0200655 if (all) {
656 /* no feature to enable */
657 return LY_SUCCESS;
658 }
Radek Krejci0af46292019-01-11 16:02:31 +0100659 LOGERR(ctx, LY_EINVAL, "Unable to switch feature since the module \"%s\" has no features.", mod->name);
Michal Vasko82c31e62020-07-17 15:30:40 +0200660 return LY_ENOTFOUND;
Radek Krejci151a5b72018-10-19 14:21:44 +0200661 }
662
Radek Krejciba03a5a2020-08-27 14:40:41 +0200663 LY_CHECK_RET(ly_set_new(&changed));
Radek Krejcica3db002018-11-01 10:31:01 +0100664 changed_count = 0;
Radek Krejci151a5b72018-10-19 14:21:44 +0200665
Radek Krejcica3db002018-11-01 10:31:01 +0100666run:
Radek Krejci14915cc2020-09-14 17:28:13 +0200667 for (disabled_count = u = 0; u < LY_ARRAY_COUNT(mod->features); ++u) {
668 f = &mod->features[u];
Radek Krejci151a5b72018-10-19 14:21:44 +0200669 if (all || !strcmp(f->name, name)) {
670 if ((value && (f->flags & LYS_FENABLED)) || (!value && !(f->flags & LYS_FENABLED))) {
671 if (all) {
672 /* skip already set features */
673 continue;
674 } else {
675 /* feature already set correctly */
Michal Vaskob0099a92020-08-31 14:55:23 +0200676 goto cleanup;
Radek Krejci151a5b72018-10-19 14:21:44 +0200677 }
678 }
679
680 if (value) { /* enable */
Michal Vasko82c31e62020-07-17 15:30:40 +0200681 if (!skip_checks) {
682 /* check referenced features if they are enabled */
683 LY_ARRAY_FOR(f->iffeatures, struct lysc_iffeature, iff) {
684 if (lysc_iffeature_value(iff) == LY_ENOT) {
685 if (all) {
686 ++disabled_count;
687 goto next;
688 } else {
Michal Vasko997f9822020-10-14 13:09:05 +0200689 LOGERR(ctx, LY_EDENIED, "Feature \"%s\" cannot be enabled since it is disabled by "
690 "its if-feature condition(s).", f->name);
Michal Vaskob0099a92020-08-31 14:55:23 +0200691 ret = LY_EDENIED;
692 goto cleanup;
Michal Vasko82c31e62020-07-17 15:30:40 +0200693 }
Radek Krejci151a5b72018-10-19 14:21:44 +0200694 }
695 }
696 }
697 /* enable the feature */
698 f->flags |= LYS_FENABLED;
699 } else { /* disable */
700 /* disable the feature */
701 f->flags &= ~LYS_FENABLED;
702 }
703
704 /* remember the changed feature */
Radek Krejci3d92e442020-10-12 12:48:13 +0200705 ret = ly_set_add(changed, f, 1, NULL);
Michal Vaskob0099a92020-08-31 14:55:23 +0200706 LY_CHECK_GOTO(ret, cleanup);
Radek Krejci151a5b72018-10-19 14:21:44 +0200707
708 if (!all) {
709 /* stop in case changing a single feature */
710 break;
711 }
712 }
713next:
714 ;
715 }
716
717 if (!all && !changed->count) {
Radek Krejci0af46292019-01-11 16:02:31 +0100718 LOGERR(ctx, LY_EINVAL, "Feature \"%s\" not found in module \"%s\".", name, mod->name);
Michal Vaskob0099a92020-08-31 14:55:23 +0200719 ret = LY_ENOTFOUND;
720 goto cleanup;
Radek Krejci151a5b72018-10-19 14:21:44 +0200721 }
722
Radek Krejcica3db002018-11-01 10:31:01 +0100723 if (value && all && disabled_count) {
724 if (changed_count == changed->count) {
725 /* no change in last run -> not able to enable all ... */
726 /* ... print errors */
Radek Krejci14915cc2020-09-14 17:28:13 +0200727 for (u = 0; disabled_count && u < LY_ARRAY_COUNT(mod->features); ++u) {
728 if (!(mod->features[u].flags & LYS_FENABLED)) {
Michal Vasko997f9822020-10-14 13:09:05 +0200729 LOGERR(ctx, LY_EDENIED, "Feature \"%s\" cannot be enabled since it is disabled by its if-feature "
730 "condition(s).", mod->features[u].name);
Radek Krejcica3db002018-11-01 10:31:01 +0100731 --disabled_count;
732 }
733 }
734 /* ... restore the original state */
735 for (u = 0; u < changed->count; ++u) {
736 f = changed->objs[u];
737 /* re-disable the feature */
738 f->flags &= ~LYS_FENABLED;
739 }
740
Michal Vaskob0099a92020-08-31 14:55:23 +0200741 ret = LY_EDENIED;
742 goto cleanup;
Radek Krejcica3db002018-11-01 10:31:01 +0100743 } else {
744 /* we did some change in last run, try it again */
745 changed_count = changed->count;
746 goto run;
747 }
748 }
749
Radek Krejci151a5b72018-10-19 14:21:44 +0200750 /* reflect change(s) in the dependent features */
Michal Vasko82c31e62020-07-17 15:30:40 +0200751 for (u = 0; !skip_checks && (u < changed->count); ++u) {
Radek Krejci151a5b72018-10-19 14:21:44 +0200752 /* If a dependent feature is enabled, it can be now changed by the change (to false) of the value of
753 * its if-feature statements. The reverse logic, automatically enable feature when its feature is enabled
754 * is not done - by default, features are disabled and must be explicitely enabled. */
755 f = changed->objs[u];
Michal Vasko22df3f02020-08-24 13:29:22 +0200756 LY_ARRAY_FOR(f->depfeatures, struct lysc_feature *, df) {
Radek Krejci151a5b72018-10-19 14:21:44 +0200757 if (!((*df)->flags & LYS_FENABLED)) {
758 /* not enabled, nothing to do */
759 continue;
760 }
761 /* check the feature's if-features which could change by the previous change of our feature */
762 LY_ARRAY_FOR((*df)->iffeatures, struct lysc_iffeature, iff) {
Michal Vasko28d78432020-05-26 13:10:53 +0200763 if (lysc_iffeature_value(iff) == LY_ENOT) {
Radek Krejci151a5b72018-10-19 14:21:44 +0200764 /* the feature must be disabled now */
765 (*df)->flags &= ~LYS_FENABLED;
766 /* add the feature into the list of changed features */
Radek Krejci3d92e442020-10-12 12:48:13 +0200767 ret = ly_set_add(changed, *df, 1, NULL);
Michal Vaskob0099a92020-08-31 14:55:23 +0200768 LY_CHECK_GOTO(ret, cleanup);
Radek Krejci151a5b72018-10-19 14:21:44 +0200769 break;
770 }
771 }
772 }
773 }
774
Michal Vasko87a97f42020-10-06 10:30:28 +0200775 /* success */
776 ++mod->ctx->module_set_id;
777
Michal Vaskob0099a92020-08-31 14:55:23 +0200778cleanup:
Radek Krejci151a5b72018-10-19 14:21:44 +0200779 ly_set_free(changed, NULL);
Michal Vaskob0099a92020-08-31 14:55:23 +0200780 return ret;
Radek Krejci151a5b72018-10-19 14:21:44 +0200781}
782
783API LY_ERR
Radek Krejcied5acc52019-04-25 15:57:04 +0200784lys_feature_enable(const struct lys_module *module, const char *feature)
Radek Krejci151a5b72018-10-19 14:21:44 +0200785{
Radek Krejci0af46292019-01-11 16:02:31 +0100786 LY_CHECK_ARG_RET(NULL, module, feature, LY_EINVAL);
Radek Krejci151a5b72018-10-19 14:21:44 +0200787
Michal Vasko22df3f02020-08-24 13:29:22 +0200788 return lys_feature_change((struct lys_module *)module, feature, 1, 0);
Radek Krejci151a5b72018-10-19 14:21:44 +0200789}
790
791API LY_ERR
Radek Krejcied5acc52019-04-25 15:57:04 +0200792lys_feature_disable(const struct lys_module *module, const char *feature)
Radek Krejci151a5b72018-10-19 14:21:44 +0200793{
Radek Krejci0af46292019-01-11 16:02:31 +0100794 LY_CHECK_ARG_RET(NULL, module, feature, LY_EINVAL);
Radek Krejci151a5b72018-10-19 14:21:44 +0200795
Michal Vasko22df3f02020-08-24 13:29:22 +0200796 return lys_feature_change((struct lys_module *)module, feature, 0, 0);
Radek Krejci151a5b72018-10-19 14:21:44 +0200797}
798
Michal Vasko82c31e62020-07-17 15:30:40 +0200799API LY_ERR
800lys_feature_enable_force(const struct lys_module *module, const char *feature)
801{
802 LY_CHECK_ARG_RET(NULL, module, feature, LY_EINVAL);
803
Michal Vasko22df3f02020-08-24 13:29:22 +0200804 return lys_feature_change((struct lys_module *)module, feature, 1, 1);
Michal Vasko82c31e62020-07-17 15:30:40 +0200805}
806
807API LY_ERR
808lys_feature_disable_force(const struct lys_module *module, const char *feature)
809{
810 LY_CHECK_ARG_RET(NULL, module, feature, LY_EINVAL);
811
Michal Vasko22df3f02020-08-24 13:29:22 +0200812 return lys_feature_change((struct lys_module *)module, feature, 0, 1);
Michal Vasko82c31e62020-07-17 15:30:40 +0200813}
814
815API LY_ERR
Radek Krejci151a5b72018-10-19 14:21:44 +0200816lys_feature_value(const struct lys_module *module, const char *feature)
817{
Michal Vasko82c31e62020-07-17 15:30:40 +0200818 struct lysc_feature *f = NULL;
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200819 LY_ARRAY_COUNT_TYPE u;
Radek Krejci151a5b72018-10-19 14:21:44 +0200820
821 LY_CHECK_ARG_RET(NULL, module, module->compiled, feature, -1);
Radek Krejci151a5b72018-10-19 14:21:44 +0200822
823 /* search for the specified feature */
Radek Krejci14915cc2020-09-14 17:28:13 +0200824 LY_ARRAY_FOR(module->features, u) {
825 f = &module->features[u];
Radek Krejci151a5b72018-10-19 14:21:44 +0200826 if (!strcmp(f->name, feature)) {
Michal Vasko82c31e62020-07-17 15:30:40 +0200827 break;
Radek Krejci151a5b72018-10-19 14:21:44 +0200828 }
829 }
830
831 /* feature definition not found */
Michal Vasko82c31e62020-07-17 15:30:40 +0200832 if (!f) {
833 return LY_ENOTFOUND;
834 }
835
836 /* feature disabled */
837 if (!(f->flags & LYS_FENABLED)) {
838 return LY_ENOT;
839 }
840
841 /* check referenced features if they are enabled */
842 LY_ARRAY_FOR(f->iffeatures, u) {
843 if (lysc_iffeature_value(&f->iffeatures[u]) == LY_ENOT) {
844 /* if-feature disabled */
845 return LY_ENOT;
846 }
847 }
848
849 /* feature enabled */
850 return LY_SUCCESS;
Radek Krejci151a5b72018-10-19 14:21:44 +0200851}
852
Michal Vaskoc193ce92020-03-06 11:04:48 +0100853API const struct lysc_node *
Radek Krejci857189e2020-09-01 13:26:36 +0200854lysc_node_is_disabled(const struct lysc_node *node, ly_bool recursive)
Radek Krejcia3045382018-11-22 14:30:31 +0100855{
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200856 LY_ARRAY_COUNT_TYPE u;
Radek Krejcia3045382018-11-22 14:30:31 +0100857
858 LY_CHECK_ARG_RET(NULL, node, NULL);
859
Michal Vaskoc193ce92020-03-06 11:04:48 +0100860 do {
Radek Krejci056d0a82018-12-06 16:57:25 +0100861 if (node->iffeatures) {
Radek Krejcia3045382018-11-22 14:30:31 +0100862 /* check local if-features */
Radek Krejci056d0a82018-12-06 16:57:25 +0100863 LY_ARRAY_FOR(node->iffeatures, u) {
Michal Vasko28d78432020-05-26 13:10:53 +0200864 if (lysc_iffeature_value(&node->iffeatures[u]) == LY_ENOT) {
Michal Vaskoc193ce92020-03-06 11:04:48 +0100865 return node;
Radek Krejcia3045382018-11-22 14:30:31 +0100866 }
867 }
868 }
869
870 if (!recursive) {
871 return NULL;
872 }
873
Michal Vaskoc193ce92020-03-06 11:04:48 +0100874 /* go through schema-only parents */
Radek Krejcia3045382018-11-22 14:30:31 +0100875 node = node->parent;
Michal Vaskoc193ce92020-03-06 11:04:48 +0100876 } while (node && (node->nodetype & (LYS_CASE | LYS_CHOICE)));
877
Radek Krejcia3045382018-11-22 14:30:31 +0100878 return NULL;
879}
880
Radek Krejci19cf8052020-08-18 15:02:38 +0200881API LY_ERR
Radek Krejciaf9cd802020-10-06 21:59:47 +0200882lysc_set_private(const struct lysc_node *node, void *priv, void **prev_priv_p)
Radek Krejci19cf8052020-08-18 15:02:38 +0200883{
Radek Krejciaf9cd802020-10-06 21:59:47 +0200884 struct lysc_action *act;
885 struct lysc_notif *notif;
886
Radek Krejci19cf8052020-08-18 15:02:38 +0200887 LY_CHECK_ARG_RET(NULL, node, LY_EINVAL);
888
Radek Krejciaf9cd802020-10-06 21:59:47 +0200889 switch (node->nodetype) {
890 case LYS_CONTAINER:
891 case LYS_CHOICE:
892 case LYS_CASE:
893 case LYS_LEAF:
894 case LYS_LEAFLIST:
895 case LYS_LIST:
896 case LYS_ANYXML:
897 case LYS_ANYDATA:
898 if (prev_priv_p) {
899 *prev_priv_p = node->priv;
900 }
901 ((struct lysc_node *)node)->priv = priv;
902 break;
903 case LYS_RPC:
904 case LYS_ACTION:
905 act = (struct lysc_action *)node;
906 if (prev_priv_p) {
907 *prev_priv_p = act->priv;
908 }
909 act->priv = priv;
910 break;
911 case LYS_NOTIF:
912 notif = (struct lysc_notif *)node;
913 if (prev_priv_p) {
914 *prev_priv_p = notif->priv;
915 }
916 notif->priv = priv;
917 break;
918 default:
919 return LY_EINVAL;
Radek Krejci19cf8052020-08-18 15:02:38 +0200920 }
Radek Krejci19cf8052020-08-18 15:02:38 +0200921
922 return LY_SUCCESS;
923}
924
Michal Vasko89b5c072020-10-06 13:52:44 +0200925API LY_ERR
926lys_set_implemented(struct lys_module *mod)
Radek Krejci77a8bcd2019-09-11 11:20:02 +0200927{
Michal Vasko89b5c072020-10-06 13:52:44 +0200928 LY_ERR ret = LY_SUCCESS, r;
Radek Krejci77a8bcd2019-09-11 11:20:02 +0200929 struct lys_module *m;
Michal Vasko89b5c072020-10-06 13:52:44 +0200930 uint32_t i, idx;
Radek Krejci77a8bcd2019-09-11 11:20:02 +0200931
932 LY_CHECK_ARG_RET(NULL, mod, LY_EINVAL);
933
934 if (mod->implemented) {
Michal Vasko89b5c072020-10-06 13:52:44 +0200935 /* mod is already implemented */
Radek Krejci77a8bcd2019-09-11 11:20:02 +0200936 return LY_SUCCESS;
937 }
938
939 /* we have module from the current context */
940 m = ly_ctx_get_module_implemented(mod->ctx, mod->name);
941 if (m) {
Michal Vasko89b5c072020-10-06 13:52:44 +0200942 assert(m != mod);
943
944 /* check collision with other implemented revision */
945 LOGERR(mod->ctx, LY_EDENIED, "Module \"%s%s%s\" is present in the context in other implemented revision (%s).",
946 mod->name, mod->revision ? "@" : "", mod->revision ? mod->revision : "", m->revision ? m->revision : "none");
947 return LY_EDENIED;
Radek Krejci77a8bcd2019-09-11 11:20:02 +0200948 }
949
Michal Vasko89b5c072020-10-06 13:52:44 +0200950 /* add the module into newly implemented module set */
Radek Krejci3d92e442020-10-12 12:48:13 +0200951 LY_CHECK_RET(ly_set_add(&mod->ctx->implementing, mod, 1, NULL));
Michal Vasko89b5c072020-10-06 13:52:44 +0200952
Radek Krejci77a8bcd2019-09-11 11:20:02 +0200953 /* mark the module implemented, check for collision was already done */
Michal Vasko89b5c072020-10-06 13:52:44 +0200954 mod->implemented = 1;
Radek Krejci77a8bcd2019-09-11 11:20:02 +0200955
956 /* compile the schema */
Michal Vasko89b5c072020-10-06 13:52:44 +0200957 ret = lys_compile(mod, 0);
Radek Krejci77a8bcd2019-09-11 11:20:02 +0200958
Michal Vasko89b5c072020-10-06 13:52:44 +0200959 if (mod == mod->ctx->implementing.objs[0]) {
960 /* the first module being implemented, consolidate the set */
961 if (ret) {
962 /* failure, full compile revert */
963 for (i = 0; i < mod->ctx->list.count; ++i) {
964 m = mod->ctx->list.objs[i];
965 if (ly_set_contains(&mod->ctx->implementing, m, &idx)) {
966 assert(m->implemented);
Radek Krejci77a8bcd2019-09-11 11:20:02 +0200967
Michal Vasko89b5c072020-10-06 13:52:44 +0200968 /* make the module correctly non-implemented again */
969 m->implemented = 0;
970 ly_set_rm_index(&mod->ctx->implementing, idx, NULL);
971 lys_precompile_augments_deviations_revert(mod->ctx, m);
972 }
973
974 /* free the compiled version of the module, if any */
975 lysc_module_free(m->compiled, NULL);
976 m->compiled = NULL;
977
978 if (m->implemented) {
979 /* recompile, must succeed because it was already compiled; hide messages because any
980 * warnings were already printed, are not really relevant, and would hide the real error */
981 uint32_t prev_lo = ly_log_options(0);
982 r = lys_compile(m, 0);
983 ly_log_options(prev_lo);
984 if (r) {
985 LOGERR(mod->ctx, r, "Recompilation of module \"%s\" failed.", m->name);
986 }
987 }
988 }
989 }
990
991 ly_set_erase(&mod->ctx->implementing, NULL);
992 }
993 return ret;
Radek Krejci77a8bcd2019-09-11 11:20:02 +0200994}
995
Michal Vasko7c8439f2020-08-05 13:25:19 +0200996static LY_ERR
997lys_resolve_import_include(struct lys_parser_ctx *pctx, struct lysp_module *modp)
998{
999 struct lysp_import *imp;
1000 struct lysp_include *inc;
1001 LY_ARRAY_COUNT_TYPE u, v;
1002
1003 modp->parsing = 1;
1004 LY_ARRAY_FOR(modp->imports, u) {
1005 imp = &modp->imports[u];
1006 if (!imp->module) {
1007 LY_CHECK_RET(lysp_load_module(PARSER_CTX(pctx), imp->name, imp->rev[0] ? imp->rev : NULL, 0, 0, &imp->module));
1008 }
1009 /* check for importing the same module twice */
1010 for (v = 0; v < u; ++v) {
1011 if (imp->module == modp->imports[v].module) {
1012 LOGWRN(PARSER_CTX(pctx), "Single revision of the module \"%s\" imported twice.", imp->name);
1013 }
1014 }
1015 }
1016 LY_ARRAY_FOR(modp->includes, u) {
1017 inc = &modp->includes[u];
1018 if (!inc->submodule) {
1019 LY_CHECK_RET(lysp_load_submodule(pctx, inc));
1020 }
1021 }
1022 modp->parsing = 0;
1023
1024 return LY_SUCCESS;
1025}
1026
Michal Vasko3a41dff2020-07-15 14:30:28 +02001027LY_ERR
Michal Vasko7a0b0762020-09-02 16:37:01 +02001028lys_parse_submodule(struct ly_ctx *ctx, struct ly_in *in, LYS_INFORMAT format, struct lys_parser_ctx *main_ctx,
Michal Vasko22df3f02020-08-24 13:29:22 +02001029 LY_ERR (*custom_check)(const struct ly_ctx *, struct lysp_module *, struct lysp_submodule *, void *),
Radek Krejci0f969882020-08-21 16:56:47 +02001030 void *check_data, struct lysp_submodule **submodule)
Radek Krejci9f5e6fb2018-10-25 09:26:12 +02001031{
Michal Vasko3a41dff2020-07-15 14:30:28 +02001032 LY_ERR ret;
Radek Krejci0bcdaed2019-01-10 10:21:34 +01001033 struct lysp_submodule *submod = NULL, *latest_sp;
Michal Vaskob36053d2020-03-26 15:49:30 +01001034 struct lys_yang_parser_ctx *yangctx = NULL;
1035 struct lys_yin_parser_ctx *yinctx = NULL;
1036 struct lys_parser_ctx *pctx;
Radek Krejci0bcdaed2019-01-10 10:21:34 +01001037
Michal Vasko3a41dff2020-07-15 14:30:28 +02001038 LY_CHECK_ARG_RET(ctx, ctx, in, LY_EINVAL);
Radek Krejci0bcdaed2019-01-10 10:21:34 +01001039
Radek Krejci0bcdaed2019-01-10 10:21:34 +01001040 switch (format) {
1041 case LYS_IN_YIN:
Michal Vasko63f3d842020-07-08 10:10:14 +02001042 ret = yin_parse_submodule(&yinctx, ctx, main_ctx, in, &submod);
Michal Vaskob36053d2020-03-26 15:49:30 +01001043 pctx = (struct lys_parser_ctx *)yinctx;
Radek Krejci0bcdaed2019-01-10 10:21:34 +01001044 break;
1045 case LYS_IN_YANG:
Michal Vasko63f3d842020-07-08 10:10:14 +02001046 ret = yang_parse_submodule(&yangctx, ctx, main_ctx, in, &submod);
Michal Vaskob36053d2020-03-26 15:49:30 +01001047 pctx = (struct lys_parser_ctx *)yangctx;
Radek Krejci0bcdaed2019-01-10 10:21:34 +01001048 break;
1049 default:
David Sedlák4f2f5ba2019-08-15 13:18:48 +02001050 LOGERR(ctx, LY_EINVAL, "Invalid schema input format.");
Radek Krejci82fa8d42020-07-11 22:00:59 +02001051 ret = LY_EINVAL;
Radek Krejci0bcdaed2019-01-10 10:21:34 +01001052 break;
Radek Krejci9f5e6fb2018-10-25 09:26:12 +02001053 }
Radek Krejcif6923e82020-07-02 16:36:53 +02001054 LY_CHECK_GOTO(ret, error);
Radek Krejcif027df72020-09-15 13:00:28 +02001055 assert(submod);
Radek Krejci0bcdaed2019-01-10 10:21:34 +01001056
1057 /* make sure that the newest revision is at position 0 */
1058 lysp_sort_revisions(submod->revs);
1059
Radek Krejci0bcdaed2019-01-10 10:21:34 +01001060 /* decide the latest revision */
Michal Vaskoc3781c32020-10-06 14:04:08 +02001061 latest_sp = ly_ctx_get_submodule(NULL, submod->mod, submod->name, NULL);
Radek Krejci0bcdaed2019-01-10 10:21:34 +01001062 if (latest_sp) {
1063 if (submod->revs) {
1064 if (!latest_sp->revs) {
1065 /* latest has no revision, so mod is anyway newer */
1066 submod->latest_revision = latest_sp->latest_revision;
Radek Krejcib3289d62019-09-18 12:21:39 +02001067 /* the latest_sp is zeroed later when the new module is being inserted into the context */
1068 } else if (strcmp(submod->revs[0].date, latest_sp->revs[0].date) > 0) {
1069 submod->latest_revision = latest_sp->latest_revision;
1070 /* the latest_sp is zeroed later when the new module is being inserted into the context */
Radek Krejci0bcdaed2019-01-10 10:21:34 +01001071 } else {
Radek Krejcib3289d62019-09-18 12:21:39 +02001072 latest_sp = NULL;
Radek Krejci0bcdaed2019-01-10 10:21:34 +01001073 }
Radek Krejcib3289d62019-09-18 12:21:39 +02001074 } else {
1075 latest_sp = NULL;
Radek Krejci0bcdaed2019-01-10 10:21:34 +01001076 }
1077 } else {
1078 submod->latest_revision = 1;
1079 }
1080
Radek Krejcib3289d62019-09-18 12:21:39 +02001081 if (custom_check) {
Michal Vasko7c8439f2020-08-05 13:25:19 +02001082 LY_CHECK_GOTO(ret = custom_check(ctx, NULL, submod, check_data), error);
Radek Krejcib3289d62019-09-18 12:21:39 +02001083 }
1084
1085 if (latest_sp) {
1086 latest_sp->latest_revision = 0;
1087 }
1088
Michal Vasko7a0b0762020-09-02 16:37:01 +02001089 lys_parser_fill_filepath(ctx, in, &submod->filepath);
1090
Michal Vasko7c8439f2020-08-05 13:25:19 +02001091 /* resolve imports and includes */
1092 LY_CHECK_GOTO(ret = lys_resolve_import_include(pctx, (struct lysp_module *)submod), error);
1093
Radek Krejci0bcdaed2019-01-10 10:21:34 +01001094 /* remap possibly changed and reallocated typedefs and groupings list back to the main context */
Michal Vaskob36053d2020-03-26 15:49:30 +01001095 memcpy(&main_ctx->tpdfs_nodes, &pctx->tpdfs_nodes, sizeof main_ctx->tpdfs_nodes);
1096 memcpy(&main_ctx->grps_nodes, &pctx->grps_nodes, sizeof main_ctx->grps_nodes);
Radek Krejci0bcdaed2019-01-10 10:21:34 +01001097
David Sedlák1b623122019-08-05 15:27:49 +02001098 if (format == LYS_IN_YANG) {
Michal Vaskob36053d2020-03-26 15:49:30 +01001099 yang_parser_ctx_free(yangctx);
David Sedlák1b623122019-08-05 15:27:49 +02001100 } else {
Michal Vaskob36053d2020-03-26 15:49:30 +01001101 yin_parser_ctx_free(yinctx);
David Sedlák1b623122019-08-05 15:27:49 +02001102 }
Michal Vasko3a41dff2020-07-15 14:30:28 +02001103 *submodule = submod;
1104 return LY_SUCCESS;
David Sedlák1b623122019-08-05 15:27:49 +02001105
Radek Krejci0bcdaed2019-01-10 10:21:34 +01001106error:
Michal Vasko5d24f6c2020-10-13 13:49:06 +02001107 lysp_module_free((struct lysp_module *)submod);
David Sedlák1b623122019-08-05 15:27:49 +02001108 if (format == LYS_IN_YANG) {
Michal Vaskob36053d2020-03-26 15:49:30 +01001109 yang_parser_ctx_free(yangctx);
David Sedlák1b623122019-08-05 15:27:49 +02001110 } else {
Michal Vaskob36053d2020-03-26 15:49:30 +01001111 yin_parser_ctx_free(yinctx);
David Sedlák1b623122019-08-05 15:27:49 +02001112 }
Michal Vasko3a41dff2020-07-15 14:30:28 +02001113 return ret;
Radek Krejci9f5e6fb2018-10-25 09:26:12 +02001114}
1115
Michal Vasko3a41dff2020-07-15 14:30:28 +02001116LY_ERR
Michal Vasko7a0b0762020-09-02 16:37:01 +02001117lys_create_module(struct ly_ctx *ctx, struct ly_in *in, LYS_INFORMAT format, ly_bool implement,
Radek Krejci1deb5be2020-08-26 16:43:36 +02001118 LY_ERR (*custom_check)(const struct ly_ctx *ctx, struct lysp_module *mod, struct lysp_submodule *submod, void *data),
1119 void *check_data, struct lys_module **module)
Radek Krejci86d106e2018-10-18 09:53:19 +02001120{
Radek Krejci6d6e4e42018-10-29 13:28:19 +01001121 struct lys_module *mod = NULL, *latest, *mod_dup;
Michal Vasko5d24f6c2020-10-13 13:49:06 +02001122 struct lysp_submodule *submod;
Michal Vasko3a41dff2020-07-15 14:30:28 +02001123 LY_ERR ret;
Michal Vasko7c8439f2020-08-05 13:25:19 +02001124 LY_ARRAY_COUNT_TYPE u;
Michal Vaskob36053d2020-03-26 15:49:30 +01001125 struct lys_yang_parser_ctx *yangctx = NULL;
1126 struct lys_yin_parser_ctx *yinctx = NULL;
Radek Krejcif6923e82020-07-02 16:36:53 +02001127 struct lys_parser_ctx *pctx = NULL;
Michal Vasko7a0b0762020-09-02 16:37:01 +02001128 char *filename, *rev, *dot;
1129 size_t len;
Radek Krejci86d106e2018-10-18 09:53:19 +02001130
Michal Vasko3a41dff2020-07-15 14:30:28 +02001131 LY_CHECK_ARG_RET(ctx, ctx, in, LY_EINVAL);
Michal Vasko7a0b0762020-09-02 16:37:01 +02001132 if (module) {
1133 *module = NULL;
1134 }
Radek Krejci86d106e2018-10-18 09:53:19 +02001135
1136 mod = calloc(1, sizeof *mod);
Michal Vasko3a41dff2020-07-15 14:30:28 +02001137 LY_CHECK_ERR_RET(!mod, LOGMEM(ctx), LY_EMEM);
Radek Krejci0bcdaed2019-01-10 10:21:34 +01001138 mod->ctx = ctx;
Radek Krejci86d106e2018-10-18 09:53:19 +02001139
1140 switch (format) {
1141 case LYS_IN_YIN:
Michal Vasko63f3d842020-07-08 10:10:14 +02001142 ret = yin_parse_module(&yinctx, in, mod);
Michal Vaskob36053d2020-03-26 15:49:30 +01001143 pctx = (struct lys_parser_ctx *)yinctx;
Radek Krejci86d106e2018-10-18 09:53:19 +02001144 break;
1145 case LYS_IN_YANG:
Michal Vasko63f3d842020-07-08 10:10:14 +02001146 ret = yang_parse_module(&yangctx, in, mod);
Michal Vaskob36053d2020-03-26 15:49:30 +01001147 pctx = (struct lys_parser_ctx *)yangctx;
Radek Krejci86d106e2018-10-18 09:53:19 +02001148 break;
1149 default:
1150 LOGERR(ctx, LY_EINVAL, "Invalid schema input format.");
Michal Vasko3a41dff2020-07-15 14:30:28 +02001151 ret = LY_EINVAL;
Radek Krejci86d106e2018-10-18 09:53:19 +02001152 break;
1153 }
Radek Krejcif6923e82020-07-02 16:36:53 +02001154 LY_CHECK_GOTO(ret, error);
Radek Krejci9f5e6fb2018-10-25 09:26:12 +02001155
1156 /* make sure that the newest revision is at position 0 */
1157 lysp_sort_revisions(mod->parsed->revs);
Radek Krejci0af46292019-01-11 16:02:31 +01001158 if (mod->parsed->revs) {
Radek Krejci011e4aa2020-09-04 15:22:31 +02001159 LY_CHECK_GOTO(ret = lydict_insert(ctx, mod->parsed->revs[0].date, 0, &mod->revision), error);
Radek Krejci0af46292019-01-11 16:02:31 +01001160 }
Radek Krejci86d106e2018-10-18 09:53:19 +02001161
Radek Krejcib3289d62019-09-18 12:21:39 +02001162 /* decide the latest revision */
Michal Vasko22df3f02020-08-24 13:29:22 +02001163 latest = (struct lys_module *)ly_ctx_get_module_latest(ctx, mod->name);
Radek Krejcib3289d62019-09-18 12:21:39 +02001164 if (latest) {
1165 if (mod->revision) {
1166 if (!latest->revision) {
1167 /* latest has no revision, so mod is anyway newer */
1168 mod->latest_revision = latest->latest_revision;
1169 /* the latest is zeroed later when the new module is being inserted into the context */
1170 } else if (strcmp(mod->revision, latest->revision) > 0) {
1171 mod->latest_revision = latest->latest_revision;
1172 /* the latest is zeroed later when the new module is being inserted into the context */
1173 } else {
1174 latest = NULL;
1175 }
1176 } else {
1177 latest = NULL;
1178 }
1179 } else {
1180 mod->latest_revision = 1;
1181 }
1182
Radek Krejci0bcdaed2019-01-10 10:21:34 +01001183 if (custom_check) {
Michal Vasko3a41dff2020-07-15 14:30:28 +02001184 LY_CHECK_GOTO(ret = custom_check(ctx, mod->parsed, NULL, check_data), error);
Radek Krejci0bcdaed2019-01-10 10:21:34 +01001185 }
1186
Radek Krejci86d106e2018-10-18 09:53:19 +02001187 if (implement) {
Radek Krejci9f5e6fb2018-10-25 09:26:12 +02001188 /* mark the loaded module implemented */
Radek Krejci0bcdaed2019-01-10 10:21:34 +01001189 if (ly_ctx_get_module_implemented(ctx, mod->name)) {
1190 LOGERR(ctx, LY_EDENIED, "Module \"%s\" is already implemented in the context.", mod->name);
Michal Vasko3a41dff2020-07-15 14:30:28 +02001191 ret = LY_EDENIED;
Radek Krejcibbe09a92018-11-08 09:36:54 +01001192 goto error;
Radek Krejcib7db73a2018-10-24 14:18:40 +02001193 }
Radek Krejci86d106e2018-10-18 09:53:19 +02001194 }
1195
Radek Krejci0bcdaed2019-01-10 10:21:34 +01001196 /* check for duplicity in the context */
Michal Vasko22df3f02020-08-24 13:29:22 +02001197 mod_dup = (struct lys_module *)ly_ctx_get_module(ctx, mod->name, mod->revision);
Radek Krejci0bcdaed2019-01-10 10:21:34 +01001198 if (mod_dup) {
1199 if (mod_dup->parsed) {
1200 /* error */
Radek Krejcid33273d2018-10-25 14:55:52 +02001201 if (mod->parsed->revs) {
Radek Krejci0bcdaed2019-01-10 10:21:34 +01001202 LOGERR(ctx, LY_EEXIST, "Module \"%s\" of revision \"%s\" is already present in the context.",
Michal Vasko69730152020-10-09 16:30:07 +02001203 mod->name, mod->parsed->revs[0].date);
Radek Krejcid33273d2018-10-25 14:55:52 +02001204 } else {
Radek Krejci0bcdaed2019-01-10 10:21:34 +01001205 LOGERR(ctx, LY_EEXIST, "Module \"%s\" with no revision is already present in the context.",
Michal Vasko69730152020-10-09 16:30:07 +02001206 mod->name);
Radek Krejcid33273d2018-10-25 14:55:52 +02001207 }
Michal Vasko3a41dff2020-07-15 14:30:28 +02001208 ret = LY_EEXIST;
Radek Krejci0bcdaed2019-01-10 10:21:34 +01001209 goto error;
1210 } else {
1211 /* add the parsed data to the currently compiled-only module in the context */
1212 mod_dup->parsed = mod->parsed;
1213 mod_dup->parsed->mod = mod_dup;
1214 mod->parsed = NULL;
1215 lys_module_free(mod, NULL);
1216 mod = mod_dup;
1217 goto finish_parsing;
Radek Krejcid33273d2018-10-25 14:55:52 +02001218 }
Radek Krejci0bcdaed2019-01-10 10:21:34 +01001219 }
Radek Krejci86d106e2018-10-18 09:53:19 +02001220
Radek Krejcif0e1ba52020-05-22 15:14:35 +02001221 switch (in->type) {
1222 case LY_IN_FILEPATH:
1223 /* check that name and revision match filename */
1224 filename = strrchr(in->method.fpath.filepath, '/');
1225 if (!filename) {
1226 filename = in->method.fpath.filepath;
1227 } else {
1228 filename++;
1229 }
1230 rev = strchr(filename, '@');
1231 dot = strrchr(filename, '.');
1232
1233 /* name */
1234 len = strlen(mod->name);
1235 if (strncmp(filename, mod->name, len) ||
Michal Vasko69730152020-10-09 16:30:07 +02001236 ((rev && (rev != &filename[len])) || (!rev && (dot != &filename[len])))) {
Radek Krejcif0e1ba52020-05-22 15:14:35 +02001237 LOGWRN(ctx, "File name \"%s\" does not match module name \"%s\".", filename, mod->name);
1238 }
1239 if (rev) {
1240 len = dot - ++rev;
Michal Vasko69730152020-10-09 16:30:07 +02001241 if (!mod->parsed->revs || (len != 10) || strncmp(mod->parsed->revs[0].date, rev, len)) {
Radek Krejcif0e1ba52020-05-22 15:14:35 +02001242 LOGWRN(ctx, "File name \"%s\" does not match module revision \"%s\".", filename,
Michal Vasko69730152020-10-09 16:30:07 +02001243 mod->parsed->revs ? mod->parsed->revs[0].date : "none");
Radek Krejcif0e1ba52020-05-22 15:14:35 +02001244 }
1245 }
1246
1247 break;
1248 case LY_IN_FD:
1249 case LY_IN_FILE:
1250 case LY_IN_MEMORY:
1251 /* nothing special to do */
1252 break;
Michal Vasko7a0b0762020-09-02 16:37:01 +02001253 case LY_IN_ERROR:
1254 LOGINT(ctx);
1255 ret = LY_EINT;
1256 goto error;
Radek Krejci096235c2019-01-11 11:12:19 +01001257 }
Radek Krejcif0e1ba52020-05-22 15:14:35 +02001258
1259 lys_parser_fill_filepath(ctx, in, &mod->filepath);
Radek Krejcif0e1ba52020-05-22 15:14:35 +02001260
Michal Vasko89b5c072020-10-06 13:52:44 +02001261 if (!implement) {
Michal Vasko7a0b0762020-09-02 16:37:01 +02001262 /* pre-compile features and identities of the module */
Michal Vasko5d24f6c2020-10-13 13:49:06 +02001263 LY_CHECK_GOTO(ret = lys_feature_precompile(NULL, ctx, mod->parsed, mod->parsed->features, &mod->features), error);
1264 LY_CHECK_GOTO(ret = lys_identity_precompile(NULL, ctx, mod->parsed, mod->parsed->identities, &mod->identities), error);
Michal Vasko7a0b0762020-09-02 16:37:01 +02001265 }
1266
1267 if (latest) {
1268 latest->latest_revision = 0;
1269 }
1270
1271 /* add into context */
Radek Krejci3d92e442020-10-12 12:48:13 +02001272 ret = ly_set_add(&ctx->list, mod, 1, NULL);
Michal Vasko7a0b0762020-09-02 16:37:01 +02001273 LY_CHECK_GOTO(ret, error);
1274 ctx->module_set_id++;
1275
1276finish_parsing:
1277 /* resolve imports and includes */
1278 LY_CHECK_GOTO(ret = lys_resolve_import_include(pctx, mod->parsed), error_ctx);
1279
Michal Vasko89b5c072020-10-06 13:52:44 +02001280 if (!implement) {
Michal Vasko7a0b0762020-09-02 16:37:01 +02001281 /* pre-compile features and identities of any submodules */
1282 LY_ARRAY_FOR(mod->parsed->includes, u) {
Michal Vasko5d24f6c2020-10-13 13:49:06 +02001283 submod = mod->parsed->includes[u].submodule;
1284 ret = lys_feature_precompile(NULL, ctx, (struct lysp_module *)submod, submod->features, &mod->features);
1285 LY_CHECK_GOTO(ret, error);
1286 ret = lys_identity_precompile(NULL, ctx, (struct lysp_module *)submod, submod->identities, &mod->identities);
1287 LY_CHECK_GOTO(ret, error);
Michal Vasko7a0b0762020-09-02 16:37:01 +02001288 }
1289 }
1290
1291 /* check name collisions - typedefs and TODO groupings */
1292 LY_CHECK_GOTO(ret = lysp_check_typedefs(pctx, mod->parsed), error_ctx);
1293
Michal Vasko89b5c072020-10-06 13:52:44 +02001294 if (implement) {
1295 /* implement (compile) */
1296 LY_CHECK_GOTO(ret = lys_set_implemented(mod), error_ctx);
Michal Vasko7a0b0762020-09-02 16:37:01 +02001297 }
1298
1299 if (format == LYS_IN_YANG) {
1300 yang_parser_ctx_free(yangctx);
1301 } else {
1302 yin_parser_ctx_free(yinctx);
1303 }
Michal Vasko3a41dff2020-07-15 14:30:28 +02001304 if (module) {
1305 *module = mod;
1306 }
1307 return LY_SUCCESS;
Michal Vasko7a0b0762020-09-02 16:37:01 +02001308
1309error_ctx:
1310 ly_set_rm(&ctx->list, mod, NULL);
1311error:
1312 lys_module_free(mod, NULL);
1313 if (pctx) {
1314 ly_set_erase(&pctx->tpdfs_nodes, NULL);
1315 }
1316 if (format == LYS_IN_YANG) {
1317 yang_parser_ctx_free(yangctx);
1318 } else {
1319 yin_parser_ctx_free(yinctx);
1320 }
1321
1322 return ret;
1323}
1324
1325API LY_ERR
1326lys_parse(struct ly_ctx *ctx, struct ly_in *in, LYS_INFORMAT format, const struct lys_module **module)
1327{
1328 if (module) {
1329 *module = NULL;
1330 }
1331 LY_CHECK_ARG_RET(NULL, ctx, in, format > LYS_IN_UNKNOWN, LY_EINVAL);
1332
1333 /* remember input position */
1334 in->func_start = in->current;
1335
1336 return lys_create_module(ctx, in, format, 1, NULL, NULL, (struct lys_module **)module);
Radek Krejci86d106e2018-10-18 09:53:19 +02001337}
1338
Michal Vasko3a41dff2020-07-15 14:30:28 +02001339API LY_ERR
1340lys_parse_mem(struct ly_ctx *ctx, const char *data, LYS_INFORMAT format, const struct lys_module **module)
Radek Krejci86d106e2018-10-18 09:53:19 +02001341{
Radek Krejci0f969882020-08-21 16:56:47 +02001342 LY_ERR ret;
Radek Krejcif0e1ba52020-05-22 15:14:35 +02001343 struct ly_in *in = NULL;
Radek Krejci86d106e2018-10-18 09:53:19 +02001344
Michal Vasko3a41dff2020-07-15 14:30:28 +02001345 LY_CHECK_ARG_RET(ctx, data, format != LYS_IN_UNKNOWN, LY_EINVAL);
Radek Krejci65639b92018-11-27 10:51:37 +01001346
Michal Vasko3a41dff2020-07-15 14:30:28 +02001347 LY_CHECK_ERR_RET(ret = ly_in_new_memory(data, &in), LOGERR(ctx, ret, "Unable to create input handler."), ret);
Radek Krejci86d106e2018-10-18 09:53:19 +02001348
Michal Vasko3a41dff2020-07-15 14:30:28 +02001349 ret = lys_parse(ctx, in, format, module);
Radek Krejcif0e1ba52020-05-22 15:14:35 +02001350 ly_in_free(in, 0);
Radek Krejci86d106e2018-10-18 09:53:19 +02001351
Michal Vasko3a41dff2020-07-15 14:30:28 +02001352 return ret;
Radek Krejci0bcdaed2019-01-10 10:21:34 +01001353}
1354
Michal Vasko3a41dff2020-07-15 14:30:28 +02001355API LY_ERR
1356lys_parse_fd(struct ly_ctx *ctx, int fd, LYS_INFORMAT format, const struct lys_module **module)
Radek Krejci86d106e2018-10-18 09:53:19 +02001357{
Radek Krejci0f969882020-08-21 16:56:47 +02001358 LY_ERR ret;
Radek Krejcif0e1ba52020-05-22 15:14:35 +02001359 struct ly_in *in = NULL;
Radek Krejci86d106e2018-10-18 09:53:19 +02001360
Michal Vasko3a41dff2020-07-15 14:30:28 +02001361 LY_CHECK_ARG_RET(ctx, fd > -1, format != LYS_IN_UNKNOWN, LY_EINVAL);
Radek Krejci86d106e2018-10-18 09:53:19 +02001362
Michal Vasko3a41dff2020-07-15 14:30:28 +02001363 LY_CHECK_ERR_RET(ret = ly_in_new_fd(fd, &in), LOGERR(ctx, ret, "Unable to create input handler."), ret);
Radek Krejci86d106e2018-10-18 09:53:19 +02001364
Michal Vasko3a41dff2020-07-15 14:30:28 +02001365 ret = lys_parse(ctx, in, format, module);
Radek Krejcif0e1ba52020-05-22 15:14:35 +02001366 ly_in_free(in, 0);
Radek Krejci86d106e2018-10-18 09:53:19 +02001367
Michal Vasko3a41dff2020-07-15 14:30:28 +02001368 return ret;
Radek Krejci86d106e2018-10-18 09:53:19 +02001369}
1370
Michal Vasko3a41dff2020-07-15 14:30:28 +02001371API LY_ERR
1372lys_parse_path(struct ly_ctx *ctx, const char *path, LYS_INFORMAT format, const struct lys_module **module)
Radek Krejcid33273d2018-10-25 14:55:52 +02001373{
Radek Krejci0f969882020-08-21 16:56:47 +02001374 LY_ERR ret;
Radek Krejcif0e1ba52020-05-22 15:14:35 +02001375 struct ly_in *in = NULL;
Radek Krejcif0e1ba52020-05-22 15:14:35 +02001376
Michal Vasko3a41dff2020-07-15 14:30:28 +02001377 LY_CHECK_ARG_RET(ctx, path, format != LYS_IN_UNKNOWN, LY_EINVAL);
Radek Krejcif0e1ba52020-05-22 15:14:35 +02001378
Michal Vasko3a41dff2020-07-15 14:30:28 +02001379 LY_CHECK_ERR_RET(ret = ly_in_new_filepath(path, 0, &in),
Michal Vasko69730152020-10-09 16:30:07 +02001380 LOGERR(ctx, ret, "Unable to create input handler for filepath %s.", path), ret);
Radek Krejcif0e1ba52020-05-22 15:14:35 +02001381
Michal Vasko3a41dff2020-07-15 14:30:28 +02001382 ret = lys_parse(ctx, in, format, module);
Radek Krejcif0e1ba52020-05-22 15:14:35 +02001383 ly_in_free(in, 0);
1384
Michal Vasko3a41dff2020-07-15 14:30:28 +02001385 return ret;
Radek Krejcid33273d2018-10-25 14:55:52 +02001386}
1387
1388API LY_ERR
Radek Krejci857189e2020-09-01 13:26:36 +02001389lys_search_localfile(const char * const *searchpaths, ly_bool cwd, const char *name, const char *revision,
Radek Krejci0f969882020-08-21 16:56:47 +02001390 char **localfile, LYS_INFORMAT *format)
Radek Krejcid33273d2018-10-25 14:55:52 +02001391{
Radek Krejci1deb5be2020-08-26 16:43:36 +02001392 LY_ERR ret = LY_EMEM;
Radek Krejcid33273d2018-10-25 14:55:52 +02001393 size_t len, flen, match_len = 0, dir_len;
Radek Krejci857189e2020-09-01 13:26:36 +02001394 ly_bool implicit_cwd = 0;
Radek Krejcid33273d2018-10-25 14:55:52 +02001395 char *wd, *wn = NULL;
1396 DIR *dir = NULL;
1397 struct dirent *file;
1398 char *match_name = NULL;
1399 LYS_INFORMAT format_aux, match_format = 0;
1400 struct ly_set *dirs;
1401 struct stat st;
1402
1403 LY_CHECK_ARG_RET(NULL, localfile, LY_EINVAL);
1404
1405 /* start to fill the dir fifo with the context's search path (if set)
1406 * and the current working directory */
Radek Krejciba03a5a2020-08-27 14:40:41 +02001407 LY_CHECK_RET(ly_set_new(&dirs));
Radek Krejcid33273d2018-10-25 14:55:52 +02001408
1409 len = strlen(name);
1410 if (cwd) {
1411 wd = get_current_dir_name();
1412 if (!wd) {
1413 LOGMEM(NULL);
1414 goto cleanup;
1415 } else {
1416 /* add implicit current working directory (./) to be searched,
1417 * this directory is not searched recursively */
Radek Krejciba03a5a2020-08-27 14:40:41 +02001418 ret = ly_set_add(dirs, wd, 0, NULL);
1419 LY_CHECK_GOTO(ret, cleanup);
Radek Krejcid33273d2018-10-25 14:55:52 +02001420 implicit_cwd = 1;
1421 }
1422 }
1423 if (searchpaths) {
Radek Krejci1deb5be2020-08-26 16:43:36 +02001424 for (uint64_t i = 0; searchpaths[i]; i++) {
Radek Krejcid33273d2018-10-25 14:55:52 +02001425 /* check for duplicities with the implicit current working directory */
1426 if (implicit_cwd && !strcmp(dirs->objs[0], searchpaths[i])) {
1427 implicit_cwd = 0;
1428 continue;
1429 }
1430 wd = strdup(searchpaths[i]);
1431 if (!wd) {
1432 LOGMEM(NULL);
1433 goto cleanup;
Radek Krejciba03a5a2020-08-27 14:40:41 +02001434 } else {
1435 ret = ly_set_add(dirs, wd, 0, NULL);
1436 LY_CHECK_GOTO(ret, cleanup);
Radek Krejcid33273d2018-10-25 14:55:52 +02001437 }
1438 }
1439 }
1440 wd = NULL;
1441
1442 /* start searching */
1443 while (dirs->count) {
1444 free(wd);
1445 free(wn); wn = NULL;
1446
1447 dirs->count--;
1448 wd = (char *)dirs->objs[dirs->count];
1449 dirs->objs[dirs->count] = NULL;
1450 LOGVRB("Searching for \"%s\" in %s.", name, wd);
1451
1452 if (dir) {
1453 closedir(dir);
1454 }
1455 dir = opendir(wd);
1456 dir_len = strlen(wd);
1457 if (!dir) {
1458 LOGWRN(NULL, "Unable to open directory \"%s\" for searching (sub)modules (%s).", wd, strerror(errno));
1459 } else {
1460 while ((file = readdir(dir))) {
1461 if (!strcmp(".", file->d_name) || !strcmp("..", file->d_name)) {
1462 /* skip . and .. */
1463 continue;
1464 }
1465 free(wn);
1466 if (asprintf(&wn, "%s/%s", wd, file->d_name) == -1) {
1467 LOGMEM(NULL);
1468 goto cleanup;
1469 }
1470 if (stat(wn, &st) == -1) {
1471 LOGWRN(NULL, "Unable to get information about \"%s\" file in \"%s\" when searching for (sub)modules (%s)",
Michal Vasko69730152020-10-09 16:30:07 +02001472 file->d_name, wd, strerror(errno));
Radek Krejcid33273d2018-10-25 14:55:52 +02001473 continue;
1474 }
1475 if (S_ISDIR(st.st_mode) && (dirs->count || !implicit_cwd)) {
1476 /* we have another subdirectory in searchpath to explore,
1477 * subdirectories are not taken into account in current working dir (dirs->set.g[0]) */
Radek Krejciba03a5a2020-08-27 14:40:41 +02001478 ret = ly_set_add(dirs, wn, 0, NULL);
1479 LY_CHECK_GOTO(ret, cleanup);
1480
Radek Krejcid33273d2018-10-25 14:55:52 +02001481 /* continue with the next item in current directory */
1482 wn = NULL;
1483 continue;
1484 } else if (!S_ISREG(st.st_mode)) {
1485 /* not a regular file (note that we see the target of symlinks instead of symlinks */
1486 continue;
1487 }
1488
1489 /* here we know that the item is a file which can contain a module */
1490 if (strncmp(name, file->d_name, len) ||
Michal Vasko69730152020-10-09 16:30:07 +02001491 ((file->d_name[len] != '.') && (file->d_name[len] != '@'))) {
Radek Krejcid33273d2018-10-25 14:55:52 +02001492 /* different filename than the module we search for */
1493 continue;
1494 }
1495
1496 /* get type according to filename suffix */
1497 flen = strlen(file->d_name);
Radek Krejcied5acc52019-04-25 15:57:04 +02001498 if (!strcmp(&file->d_name[flen - 5], ".yang")) {
Radek Krejcid33273d2018-10-25 14:55:52 +02001499 format_aux = LYS_IN_YANG;
Radek Krejci0f969882020-08-21 16:56:47 +02001500 /* TODO YIN parser
1501 } else if (!strcmp(&file->d_name[flen - 4], ".yin")) {
1502 format_aux = LYS_IN_YIN;
1503 */
Radek Krejcid33273d2018-10-25 14:55:52 +02001504 } else {
1505 /* not supportde suffix/file format */
1506 continue;
1507 }
1508
1509 if (revision) {
1510 /* we look for the specific revision, try to get it from the filename */
1511 if (file->d_name[len] == '@') {
1512 /* check revision from the filename */
1513 if (strncmp(revision, &file->d_name[len + 1], strlen(revision))) {
1514 /* another revision */
1515 continue;
1516 } else {
1517 /* exact revision */
1518 free(match_name);
1519 match_name = wn;
1520 wn = NULL;
1521 match_len = dir_len + 1 + len;
1522 match_format = format_aux;
1523 goto success;
1524 }
1525 } else {
1526 /* continue trying to find exact revision match, use this only if not found */
1527 free(match_name);
1528 match_name = wn;
1529 wn = NULL;
Michal Vasko44f3d2c2020-08-24 09:49:38 +02001530 match_len = dir_len + 1 + len;
Radek Krejcid33273d2018-10-25 14:55:52 +02001531 match_format = format_aux;
1532 continue;
1533 }
1534 } else {
1535 /* remember the revision and try to find the newest one */
1536 if (match_name) {
Michal Vasko69730152020-10-09 16:30:07 +02001537 if ((file->d_name[len] != '@') ||
1538 lysp_check_date(NULL, &file->d_name[len + 1], flen - ((format_aux == LYS_IN_YANG) ? 5 : 4) - len - 1, NULL)) {
Radek Krejcid33273d2018-10-25 14:55:52 +02001539 continue;
Michal Vasko69730152020-10-09 16:30:07 +02001540 } else if ((match_name[match_len] == '@') &&
Radek Krejcid33273d2018-10-25 14:55:52 +02001541 (strncmp(&match_name[match_len + 1], &file->d_name[len + 1], LY_REV_SIZE - 1) >= 0)) {
1542 continue;
1543 }
1544 free(match_name);
1545 }
1546
1547 match_name = wn;
1548 wn = NULL;
1549 match_len = dir_len + 1 + len;
1550 match_format = format_aux;
1551 continue;
1552 }
1553 }
1554 }
1555 }
1556
1557success:
1558 (*localfile) = match_name;
1559 match_name = NULL;
1560 if (format) {
1561 (*format) = match_format;
1562 }
Radek Krejci1deb5be2020-08-26 16:43:36 +02001563 ret = LY_SUCCESS;
Radek Krejcid33273d2018-10-25 14:55:52 +02001564
1565cleanup:
1566 free(wn);
1567 free(wd);
1568 if (dir) {
1569 closedir(dir);
1570 }
1571 free(match_name);
1572 ly_set_free(dirs, free);
1573
1574 return ret;
1575}