blob: 8c0925e1aa689788815535557de5903e128d933f [file] [log] [blame]
Radek Krejcida04f4a2015-05-21 12:54:09 +02001/**
2 * @file context.c
3 * @author Radek Krejci <rkrejci@cesnet.cz>
4 * @brief context implementation for libyang
5 *
6 * Copyright (c) 2015 CESNET, z.s.p.o.
7 *
Radek Krejci54f6fb32016-02-24 12:56:39 +01008 * This source code is licensed under BSD 3-Clause License (the "License").
9 * You may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
Michal Vasko8de098c2016-02-26 10:00:25 +010011 *
Radek Krejci54f6fb32016-02-24 12:56:39 +010012 * https://opensource.org/licenses/BSD-3-Clause
Radek Krejcida04f4a2015-05-21 12:54:09 +020013 */
14
15#define _GNU_SOURCE
Radek Krejcicf748252017-09-04 11:11:14 +020016#include <pthread.h>
Radek Krejcifd4e6e32015-08-10 15:00:51 +020017#include <stddef.h>
Radek Krejcida04f4a2015-05-21 12:54:09 +020018#include <stdlib.h>
19#include <string.h>
20#include <sys/types.h>
21#include <sys/stat.h>
22#include <unistd.h>
23#include <errno.h>
24#include <fcntl.h>
25
26#include "common.h"
27#include "context.h"
Radek Krejci41912fe2015-10-22 10:22:12 +020028#include "dict_private.h"
Michal Vasko209a6222015-10-16 09:51:07 +020029#include "parser.h"
Radek Krejcibc9cf932015-07-30 11:09:39 +020030#include "tree_internal.h"
Radek Krejci83a4bac2017-02-07 15:53:04 +010031#include "resolve.h"
Radek Krejcida04f4a2015-05-21 12:54:09 +020032
Radek Krejci858ad952017-01-04 11:16:32 +010033/*
34 * counter for references to the extensions plugins (for the number of contexts)
35 * located in extensions.c
36 */
37extern unsigned int ext_plugins_ref;
38
Radek Krejci532e5e92017-02-22 12:59:24 +010039#define IETF_YANG_METADATA_PATH "../models/ietf-yang-metadata@2016-08-05.h"
40#define YANG_PATH "../models/yang@2017-02-20.h"
Michal Vasko8d054e42015-08-03 12:42:06 +020041#define IETF_INET_TYPES_PATH "../models/ietf-inet-types@2013-07-15.h"
Michal Vasko21181c42015-08-03 13:46:45 +020042#define IETF_YANG_TYPES_PATH "../models/ietf-yang-types@2013-07-15.h"
Radek Krejcidfb00d62017-09-06 09:39:35 +020043#define IETF_DATASTORES "../models/ietf-datastores@2017-08-17.h"
Michal Vaskoeb3bd0e2018-01-26 11:52:11 +010044#define IETF_YANG_LIB_PATH "../models/ietf-yang-library@2018-01-17.h"
45#define IETF_YANG_LIB_REV "2018-01-17"
Michal Vasko8d054e42015-08-03 12:42:06 +020046
Radek Krejci532e5e92017-02-22 12:59:24 +010047#include IETF_YANG_METADATA_PATH
48#include YANG_PATH
Michal Vasko8d054e42015-08-03 12:42:06 +020049#include IETF_INET_TYPES_PATH
Michal Vasko21181c42015-08-03 13:46:45 +020050#include IETF_YANG_TYPES_PATH
Radek Krejcidfb00d62017-09-06 09:39:35 +020051#include IETF_DATASTORES
Michal Vasko8d054e42015-08-03 12:42:06 +020052#include IETF_YANG_LIB_PATH
53
Radek Krejcidfb00d62017-09-06 09:39:35 +020054#define LY_INTERNAL_MODULE_COUNT 6
Radek Krejci03203412016-06-23 15:20:53 +020055static struct internal_modules_s {
56 const char *name;
57 const char *revision;
58 const char *data;
59 uint8_t implemented;
60 LYS_INFORMAT format;
Michal Vasko2d051a12017-04-21 09:28:57 +020061} internal_modules[LY_INTERNAL_MODULE_COUNT] = {
Radek Krejci532e5e92017-02-22 12:59:24 +010062 {"ietf-yang-metadata", "2016-08-05", (const char*)ietf_yang_metadata_2016_08_05_yin, 0, LYS_IN_YIN},
63 {"yang", "2017-02-20", (const char*)yang_2017_02_20_yin, 1, LYS_IN_YIN},
Radek Krejci03203412016-06-23 15:20:53 +020064 {"ietf-inet-types", "2013-07-15", (const char*)ietf_inet_types_2013_07_15_yin, 0, LYS_IN_YIN},
65 {"ietf-yang-types", "2013-07-15", (const char*)ietf_yang_types_2013_07_15_yin, 0, LYS_IN_YIN},
Radek Krejcidfb00d62017-09-06 09:39:35 +020066 /* ietf-datastores and ietf-yang-library must be right here at the end of the list! */
67 {"ietf-datastores", "2017-08-17", (const char*)ietf_datastores_2017_08_17_yin, 0, LYS_IN_YIN},
Michal Vaskoeb3bd0e2018-01-26 11:52:11 +010068 {"ietf-yang-library", IETF_YANG_LIB_REV, (const char*)ietf_yang_library_2018_01_17_yin, 1, LYS_IN_YIN}
Radek Krejci03203412016-06-23 15:20:53 +020069};
70
Radek Krejcidfb00d62017-09-06 09:39:35 +020071API unsigned int
72ly_ctx_internal_modules_count(struct ly_ctx *ctx)
73{
74 if (!ctx) {
75 return 0;
76 }
77 return ctx->internal_module_count;
78}
79
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020080API struct ly_ctx *
Radek Krejcidd3263a2017-07-15 11:50:09 +020081ly_ctx_new(const char *search_dir, int options)
Radek Krejcida04f4a2015-05-21 12:54:09 +020082{
Radek Krejcia8d111f2017-05-31 13:57:37 +020083 struct ly_ctx *ctx = NULL;
Michal Vasko7d7de952016-05-02 17:13:14 +020084 struct lys_module *module;
Radek Krejcia8d111f2017-05-31 13:57:37 +020085 char *cwd = NULL;
Igor Ternovsky9a10e1a2017-09-11 12:53:04 +100086 char *search_dir_list;
87 char *sep, *dir;
Igor Ternovsky6e6543d2017-09-12 10:37:28 +100088 int rc = EXIT_SUCCESS;
Radek Krejci03203412016-06-23 15:20:53 +020089 int i;
Radek Krejcida04f4a2015-05-21 12:54:09 +020090
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020091 ctx = calloc(1, sizeof *ctx);
Michal Vasko53b7da02018-02-13 15:28:42 +010092 LY_CHECK_ERR_RETURN(!ctx, LOGMEM(NULL), NULL);
Radek Krejcida04f4a2015-05-21 12:54:09 +020093
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020094 /* dictionary */
95 lydict_init(&ctx->dict);
Radek Krejcida04f4a2015-05-21 12:54:09 +020096
Radek Krejci858ad952017-01-04 11:16:32 +010097 /* plugins */
Michal Vaskoc6cd3f02018-03-02 14:07:42 +010098 ly_load_plugins();
Radek Krejci858ad952017-01-04 11:16:32 +010099
Radek Krejcicf748252017-09-04 11:11:14 +0200100 /* initialize thread-specific key */
101 while ((i = pthread_key_create(&ctx->errlist_key, ly_err_free)) == EAGAIN);
102
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200103 /* models list */
104 ctx->models.list = calloc(16, sizeof *ctx->models.list);
Michal Vasko53b7da02018-02-13 15:28:42 +0100105 LY_CHECK_ERR_RETURN(!ctx->models.list, LOGMEM(NULL); free(ctx), NULL);
Radek Krejcidd3263a2017-07-15 11:50:09 +0200106 ctx->models.flags = options;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200107 ctx->models.used = 0;
108 ctx->models.size = 16;
109 if (search_dir) {
Igor Ternovsky9a10e1a2017-09-11 12:53:04 +1000110 search_dir_list = strdup(search_dir);
Michal Vasko53b7da02018-02-13 15:28:42 +0100111 LY_CHECK_ERR_GOTO(!search_dir_list, LOGMEM(NULL), error);
Igor Ternovsky9a10e1a2017-09-11 12:53:04 +1000112
Igor Ternovsky6e6543d2017-09-12 10:37:28 +1000113 for (dir = search_dir_list; (sep = strchr(dir, ':')) != NULL && rc == EXIT_SUCCESS; dir = sep + 1) {
Igor Ternovsky9a10e1a2017-09-11 12:53:04 +1000114 *sep = 0;
Igor Ternovsky6e6543d2017-09-12 10:37:28 +1000115 rc = ly_ctx_set_searchdir(ctx, dir);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200116 }
Igor Ternovsky6e6543d2017-09-12 10:37:28 +1000117 if (*dir && rc == EXIT_SUCCESS) {
118 rc = ly_ctx_set_searchdir(ctx, dir);
Radek Krejci15412ca2016-03-03 11:16:52 +0100119 }
Igor Ternovsky9a10e1a2017-09-11 12:53:04 +1000120 free(search_dir_list);
Igor Ternovsky6e6543d2017-09-12 10:37:28 +1000121 /* If ly_ctx_set_searchdir() failed, the error is already logged. Just exit */
122 if (rc != EXIT_SUCCESS) {
123 goto error;
124 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200125 }
Michal Vasko14719b22015-08-03 12:47:55 +0200126 ctx->models.module_set_id = 1;
127
Radek Krejci03203412016-06-23 15:20:53 +0200128 /* load internal modules */
Radek Krejcidfb00d62017-09-06 09:39:35 +0200129 if (options & LY_CTX_NOYANGLIBRARY) {
130 ctx->internal_module_count = LY_INTERNAL_MODULE_COUNT - 2;
131 } else {
132 ctx->internal_module_count = LY_INTERNAL_MODULE_COUNT;
133 }
134 for (i = 0; i < ctx->internal_module_count; i++) {
Radek Krejci03203412016-06-23 15:20:53 +0200135 module = (struct lys_module *)lys_parse_mem(ctx, internal_modules[i].data, internal_modules[i].format);
136 if (!module) {
Radek Krejcia8d111f2017-05-31 13:57:37 +0200137 goto error;
Radek Krejci03203412016-06-23 15:20:53 +0200138 }
139 module->implemented = internal_modules[i].implemented;
Michal Vasko8d054e42015-08-03 12:42:06 +0200140 }
Radek Krejcida04f4a2015-05-21 12:54:09 +0200141
Radek Krejcia8d111f2017-05-31 13:57:37 +0200142 /* cleanup */
143 free(cwd);
144
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200145 return ctx;
Radek Krejcia8d111f2017-05-31 13:57:37 +0200146
147error:
148 free(cwd);
149 ly_ctx_destroy(ctx, NULL);
150 return NULL;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200151}
152
Michal Vaskoeb3bd0e2018-01-26 11:52:11 +0100153static int
154ly_ctx_new_yl_legacy(struct ly_ctx *ctx, struct lyd_node *yltree)
Radek Krejci69333c92017-03-17 16:14:43 +0100155{
Michal Vasko60d400b2017-12-13 11:14:39 +0100156 unsigned int i, u;
Radek Krejci69333c92017-03-17 16:14:43 +0100157 struct lyd_node *module, *node;
Michal Vaskoeb3bd0e2018-01-26 11:52:11 +0100158 struct ly_set *set;
Radek Krejci69333c92017-03-17 16:14:43 +0100159 const char *name, *revision;
Radek Krejci5cb217d2017-03-25 16:07:52 -0500160 struct ly_set features = {0, 0, {NULL}};
Radek Krejci69333c92017-03-17 16:14:43 +0100161 const struct lys_module *mod;
Radek Krejci69333c92017-03-17 16:14:43 +0100162
Michal Vaskoeb3bd0e2018-01-26 11:52:11 +0100163 set = lyd_find_path(yltree, "/ietf-yang-library:yang-library/modules-state/module");
Michal Vasko60d400b2017-12-13 11:14:39 +0100164 if (!set) {
Michal Vaskoeb3bd0e2018-01-26 11:52:11 +0100165 return 1;
Michal Vasko60d400b2017-12-13 11:14:39 +0100166 }
167
Radek Krejci69333c92017-03-17 16:14:43 +0100168 /* process the data tree */
Michal Vasko60d400b2017-12-13 11:14:39 +0100169 for (i = 0; i < set->number; ++i) {
170 module = set->set.d[i];
Radek Krejci69333c92017-03-17 16:14:43 +0100171
172 /* initiate */
173 name = NULL;
174 revision = NULL;
175 ly_set_clean(&features);
176
177 LY_TREE_FOR(module->child, node) {
178 if (!strcmp(node->schema->name, "name")) {
179 name = ((struct lyd_node_leaf_list*)node)->value_str;
180 } else if (!strcmp(node->schema->name, "revision")) {
181 revision = ((struct lyd_node_leaf_list*)node)->value_str;
182 } else if (!strcmp(node->schema->name, "feature")) {
183 ly_set_add(&features, node, LY_SET_OPT_USEASLIST);
184 } else if (!strcmp(node->schema->name, "conformance-type") &&
185 ((struct lyd_node_leaf_list*)node)->value.enm->value) {
186 /* imported module - skip it, it will be loaded as a side effect
187 * of loading another module */
Michal Vasko60d400b2017-12-13 11:14:39 +0100188 continue;
Radek Krejci69333c92017-03-17 16:14:43 +0100189 }
190 }
191
192 /* use the gathered data to load the module */
193 mod = ly_ctx_load_module(ctx, name, revision);
194 if (!mod) {
Michal Vasko53b7da02018-02-13 15:28:42 +0100195 LOGERR(ctx, LY_EINVAL, "Unable to load module specified by yang library data.");
Michal Vaskoeb3bd0e2018-01-26 11:52:11 +0100196 ly_set_free(set);
197 return 1;
Radek Krejci69333c92017-03-17 16:14:43 +0100198 }
199
200 /* set features */
201 for (u = 0; u < features.number; u++) {
202 lys_features_enable(mod, ((struct lyd_node_leaf_list*)features.set.d[u])->value_str);
203 }
Radek Krejci69333c92017-03-17 16:14:43 +0100204 }
205
Michal Vaskoeb3bd0e2018-01-26 11:52:11 +0100206 ly_set_free(set);
207 return 0;
208}
209
210static struct ly_ctx *
211ly_ctx_new_yl_common(const char *search_dir, const char *input, LYD_FORMAT format, int options,
212 struct lyd_node* (*parser_func)(struct ly_ctx*, const char*, LYD_FORMAT, int,...))
213{
214 unsigned int i, u;
215 struct lyd_node *module, *node;
216 const char *name, *revision;
217 struct ly_set features = {0, 0, {NULL}};
218 const struct lys_module *mod;
219 struct lyd_node *yltree = NULL;
220 struct ly_ctx *ctx = NULL;
221 struct ly_set *set = NULL;
222
223 /* create empty (with internal modules including ietf-yang-library) context */
224 ctx = ly_ctx_new(search_dir, options);
225 if (!ctx) {
226 goto error;
227 }
228
229 /* parse yang library data tree */
230 yltree = parser_func(ctx, input, format, LYD_OPT_DATA, NULL);
231 if (!yltree) {
232 goto error;
233 }
234
235 set = lyd_find_path(yltree, "/ietf-yang-library:yang-library/module-set[1]/module");
236 if (!set) {
237 goto error;
238 }
239
240 if (set->number == 0) {
241 /* perhaps a legacy data tree? */
242 if (ly_ctx_new_yl_legacy(ctx, yltree)) {
243 goto error;
244 }
245 } else {
246 /* process the data tree */
247 for (i = 0; i < set->number; ++i) {
248 module = set->set.d[i];
249
250 /* initiate */
251 name = NULL;
252 revision = NULL;
253 ly_set_clean(&features);
254
255 LY_TREE_FOR(module->child, node) {
256 if (!strcmp(node->schema->name, "name")) {
257 name = ((struct lyd_node_leaf_list*)node)->value_str;
258 } else if (!strcmp(node->schema->name, "revision")) {
259 revision = ((struct lyd_node_leaf_list*)node)->value_str;
260 } else if (!strcmp(node->schema->name, "feature")) {
261 ly_set_add(&features, node->child, LY_SET_OPT_USEASLIST);
262 }
263 }
264
265 /* use the gathered data to load the module */
266 mod = ly_ctx_load_module(ctx, name, revision);
267 if (!mod) {
Michal Vasko53b7da02018-02-13 15:28:42 +0100268 LOGERR(NULL, LY_EINVAL, "Unable to load module specified by yang library data.");
Michal Vaskoeb3bd0e2018-01-26 11:52:11 +0100269 goto error;
270 }
271
272 /* set features */
273 for (u = 0; u < features.number; u++) {
274 lys_features_enable(mod, ((struct lyd_node_leaf_list*)features.set.d[u])->value_str);
275 }
276 }
277 }
278
Radek Krejci69333c92017-03-17 16:14:43 +0100279 if (0) {
280 /* skip context destroy in case of success */
281error:
282 ly_ctx_destroy(ctx, NULL);
283 ctx = NULL;
284 }
285
286 /* cleanup */
287 if (yltree) {
288 /* yang library data tree */
289 lyd_free_withsiblings(yltree);
290 }
Michal Vasko60d400b2017-12-13 11:14:39 +0100291 if (set) {
292 ly_set_free(set);
293 }
Radek Krejci69333c92017-03-17 16:14:43 +0100294
295 return ctx;
296}
297
298API struct ly_ctx *
Radek Krejcidd3263a2017-07-15 11:50:09 +0200299ly_ctx_new_ylpath(const char *search_dir, const char *path, LYD_FORMAT format, int options)
Radek Krejci69333c92017-03-17 16:14:43 +0100300{
Radek Krejcidd3263a2017-07-15 11:50:09 +0200301 return ly_ctx_new_yl_common(search_dir, path, format, options, lyd_parse_path);
Radek Krejci69333c92017-03-17 16:14:43 +0100302}
303
304API struct ly_ctx *
Radek Krejcidd3263a2017-07-15 11:50:09 +0200305ly_ctx_new_ylmem(const char *search_dir, const char *data, LYD_FORMAT format, int options)
Radek Krejci69333c92017-03-17 16:14:43 +0100306{
Radek Krejcidd3263a2017-07-15 11:50:09 +0200307 return ly_ctx_new_yl_common(search_dir, data, format, options, lyd_parse_mem);
308}
309
310static void
311ly_ctx_set_option(struct ly_ctx *ctx, int options)
312{
313 if (!ctx) {
314 return;
315 }
316
317 ctx->models.flags |= options;
318}
319
320static void
321ly_ctx_unset_option(struct ly_ctx *ctx, int options)
322{
323 if (!ctx) {
324 return;
325 }
326
327 ctx->models.flags &= ~options;
Radek Krejci69333c92017-03-17 16:14:43 +0100328}
329
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200330API void
Radek Krejci819dd4b2017-03-07 15:35:48 +0100331ly_ctx_set_allimplemented(struct ly_ctx *ctx)
332{
Radek Krejcidd3263a2017-07-15 11:50:09 +0200333 ly_ctx_set_option(ctx, LY_CTX_ALLIMPLEMENTED);
Radek Krejci819dd4b2017-03-07 15:35:48 +0100334}
335
336API void
337ly_ctx_unset_allimplemented(struct ly_ctx *ctx)
338{
Radek Krejcidd3263a2017-07-15 11:50:09 +0200339 ly_ctx_unset_option(ctx, LY_CTX_ALLIMPLEMENTED);
340}
Radek Krejci819dd4b2017-03-07 15:35:48 +0100341
Radek Krejcidd3263a2017-07-15 11:50:09 +0200342API void
343ly_ctx_set_trusted(struct ly_ctx *ctx)
344{
345 ly_ctx_set_option(ctx, LY_CTX_TRUSTED);
346}
347
348API void
349ly_ctx_unset_trusted(struct ly_ctx *ctx)
350{
351 ly_ctx_unset_option(ctx, LY_CTX_TRUSTED);
Radek Krejci819dd4b2017-03-07 15:35:48 +0100352}
353
Igor Ternovsky6e6543d2017-09-12 10:37:28 +1000354API int
Michal Vasko60ba9a62015-07-03 14:42:31 +0200355ly_ctx_set_searchdir(struct ly_ctx *ctx, const char *search_dir)
356{
Radek Krejcia62a9d12017-08-09 12:37:51 +0200357 char *cwd = NULL, *new = NULL;
Radek Krejcida9f8392017-03-25 19:40:56 -0500358 int index = 0;
359 void *r;
Igor Ternovsky6e6543d2017-09-12 10:37:28 +1000360 int rc = EXIT_FAILURE;
Michal Vasko60ba9a62015-07-03 14:42:31 +0200361
362 if (!ctx) {
Michal Vasko53b7da02018-02-13 15:28:42 +0100363 LOGARG;
Igor Ternovsky6e6543d2017-09-12 10:37:28 +1000364 return EXIT_FAILURE;
Michal Vasko60ba9a62015-07-03 14:42:31 +0200365 }
366
367 if (search_dir) {
368 cwd = get_current_dir_name();
369 if (chdir(search_dir)) {
Michal Vasko53b7da02018-02-13 15:28:42 +0100370 LOGERR(ctx, LY_ESYS, "Unable to use search directory \"%s\" (%s)",
Michal Vasko60ba9a62015-07-03 14:42:31 +0200371 search_dir, strerror(errno));
Radek Krejcia8d111f2017-05-31 13:57:37 +0200372 goto cleanup;
Michal Vasko60ba9a62015-07-03 14:42:31 +0200373 }
Radek Krejcida9f8392017-03-25 19:40:56 -0500374
Radek Krejci426ea2b2017-06-13 12:41:51 +0200375 new = get_current_dir_name();
Radek Krejcida9f8392017-03-25 19:40:56 -0500376 if (!ctx->models.search_paths) {
377 ctx->models.search_paths = malloc(2 * sizeof *ctx->models.search_paths);
Michal Vasko53b7da02018-02-13 15:28:42 +0100378 LY_CHECK_ERR_GOTO(!ctx->models.search_paths, LOGMEM(ctx), cleanup);
Radek Krejcida9f8392017-03-25 19:40:56 -0500379 index = 0;
380 } else {
Radek Krejci426ea2b2017-06-13 12:41:51 +0200381 for (index = 0; ctx->models.search_paths[index]; index++) {
382 /* check for duplicities */
383 if (!strcmp(new, ctx->models.search_paths[index])) {
384 /* path is already present */
Radek Krejci426ea2b2017-06-13 12:41:51 +0200385 goto success;
386 }
387 }
Radek Krejcida9f8392017-03-25 19:40:56 -0500388 r = realloc(ctx->models.search_paths, (index + 2) * sizeof *ctx->models.search_paths);
Michal Vasko53b7da02018-02-13 15:28:42 +0100389 LY_CHECK_ERR_GOTO(!r, LOGMEM(ctx), cleanup);
Radek Krejcida9f8392017-03-25 19:40:56 -0500390 ctx->models.search_paths = r;
391 }
Radek Krejci426ea2b2017-06-13 12:41:51 +0200392 ctx->models.search_paths[index] = new;
Radek Krejcia62a9d12017-08-09 12:37:51 +0200393 new = NULL;
Radek Krejcida9f8392017-03-25 19:40:56 -0500394 ctx->models.search_paths[index + 1] = NULL;
Michal Vasko3eff9322015-11-10 11:02:30 +0100395
Radek Krejci426ea2b2017-06-13 12:41:51 +0200396success:
Radek Krejci15412ca2016-03-03 11:16:52 +0100397 if (chdir(cwd)) {
Michal Vasko53b7da02018-02-13 15:28:42 +0100398 LOGWRN(ctx, "Unable to return back to working directory \"%s\" (%s)",
Radek Krejci15412ca2016-03-03 11:16:52 +0100399 cwd, strerror(errno));
400 }
Igor Ternovsky6e6543d2017-09-12 10:37:28 +1000401 rc = EXIT_SUCCESS;
Radek Krejci9287c702017-09-12 10:32:24 +0200402 } else {
403 /* consider that no change is not actually an error */
404 return EXIT_SUCCESS;
Michal Vasko60ba9a62015-07-03 14:42:31 +0200405 }
Radek Krejcia8d111f2017-05-31 13:57:37 +0200406
407cleanup:
408 free(cwd);
Radek Krejcia62a9d12017-08-09 12:37:51 +0200409 free(new);
Igor Ternovsky6e6543d2017-09-12 10:37:28 +1000410 return rc;
Michal Vasko60ba9a62015-07-03 14:42:31 +0200411}
412
Radek Krejci426ea2b2017-06-13 12:41:51 +0200413API const char * const *
414ly_ctx_get_searchdirs(const struct ly_ctx *ctx)
Radek Krejci5a797572015-10-21 15:45:45 +0200415{
Radek Krejciee554172016-12-14 10:29:06 +0100416 if (!ctx) {
Michal Vasko53b7da02018-02-13 15:28:42 +0100417 LOGARG;
Radek Krejciee554172016-12-14 10:29:06 +0100418 return NULL;
419 }
Radek Krejci426ea2b2017-06-13 12:41:51 +0200420 return (const char * const *)ctx->models.search_paths;
Radek Krejcida9f8392017-03-25 19:40:56 -0500421}
422
423API void
Radek Krejcidb4e9ff2017-06-13 16:26:14 +0200424ly_ctx_unset_searchdirs(struct ly_ctx *ctx, int index)
Radek Krejcida9f8392017-03-25 19:40:56 -0500425{
426 int i;
427
428 if (!ctx->models.search_paths) {
429 return;
430 }
431
432 for (i = 0; ctx->models.search_paths[i]; i++) {
Radek Krejcidb4e9ff2017-06-13 16:26:14 +0200433 if (index < 0 || index == i) {
434 free(ctx->models.search_paths[i]);
435 ctx->models.search_paths[i] = NULL;
436 } else if (i > index) {
437 ctx->models.search_paths[i - 1] = ctx->models.search_paths[i];
438 ctx->models.search_paths[i] = NULL;
439 }
Radek Krejcida9f8392017-03-25 19:40:56 -0500440 }
Radek Krejcidb4e9ff2017-06-13 16:26:14 +0200441 if (index < 0 || !ctx->models.search_paths[0]) {
442 free(ctx->models.search_paths);
443 ctx->models.search_paths = NULL;
444 }
Radek Krejci5a797572015-10-21 15:45:45 +0200445}
446
Michal Vasko60ba9a62015-07-03 14:42:31 +0200447API void
Radek Krejcifa0b5e02016-02-04 13:57:03 +0100448ly_ctx_destroy(struct ly_ctx *ctx, void (*private_destructor)(const struct lys_node *node, void *priv))
Radek Krejcida04f4a2015-05-21 12:54:09 +0200449{
Radek Krejcida9f8392017-03-25 19:40:56 -0500450 int i;
451
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200452 if (!ctx) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200453 return;
454 }
Radek Krejcida04f4a2015-05-21 12:54:09 +0200455
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200456 /* models list */
Radek Krejcic436a232017-02-08 14:43:11 +0100457 for (; ctx->models.used > 0; ctx->models.used--) {
Radek Krejcifc8411a2017-02-03 10:26:05 +0100458 /* remove the applied deviations and augments */
Radek Krejcic436a232017-02-08 14:43:11 +0100459 lys_sub_module_remove_devs_augs(ctx->models.list[ctx->models.used - 1]);
Radek Krejcifc8411a2017-02-03 10:26:05 +0100460 /* remove the module */
Michal Vasko10681e82018-01-16 14:54:16 +0100461 lys_free(ctx->models.list[ctx->models.used - 1], private_destructor, 1, 0);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200462 }
Radek Krejcida9f8392017-03-25 19:40:56 -0500463 if (ctx->models.search_paths) {
464 for(i = 0; ctx->models.search_paths[i]; i++) {
465 free(ctx->models.search_paths[i]);
466 }
467 free(ctx->models.search_paths);
468 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200469 free(ctx->models.list);
Radek Krejcida04f4a2015-05-21 12:54:09 +0200470
Radek Krejcicf748252017-09-04 11:11:14 +0200471 /* clean the error list */
472 ly_err_clean(ctx, 0);
473 pthread_key_delete(ctx->errlist_key);
474
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200475 /* dictionary */
476 lydict_clean(&ctx->dict);
Radek Krejcida04f4a2015-05-21 12:54:09 +0200477
Radek Krejci858ad952017-01-04 11:16:32 +0100478 /* plugins - will be removed only if this is the last context */
Michal Vaskoc6cd3f02018-03-02 14:07:42 +0100479 ly_clean_plugins();
Radek Krejci858ad952017-01-04 11:16:32 +0100480
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200481 free(ctx);
Radek Krejcida04f4a2015-05-21 12:54:09 +0200482}
483
Michal Vasko1e62a092015-12-01 12:27:20 +0100484API const struct lys_submodule *
Radek Krejci62f0da72016-03-07 11:35:43 +0100485ly_ctx_get_submodule2(const struct lys_module *main_module, const char *submodule)
486{
Radek Krejcid4c1d0f2017-01-19 16:11:38 +0100487 const struct lys_submodule *result;
Radek Krejci62f0da72016-03-07 11:35:43 +0100488 int i;
489
490 if (!main_module || !submodule) {
Michal Vasko53b7da02018-02-13 15:28:42 +0100491 LOGARG;
Radek Krejci62f0da72016-03-07 11:35:43 +0100492 return NULL;
493 }
494
495 /* search in submodules list */
496 for (i = 0; i < main_module->inc_size; i++) {
497 result = main_module->inc[i].submodule;
Radek Krejcid4c1d0f2017-01-19 16:11:38 +0100498 if (ly_strequal(submodule, result->name, 0)) {
Radek Krejci62f0da72016-03-07 11:35:43 +0100499 return result;
500 }
Radek Krejcid4c1d0f2017-01-19 16:11:38 +0100501
502 /* in YANG 1.1 all the submodules must be included in the main module, so we are done.
503 * YANG 1.0 allows (is unclear about denying it) to include a submodule only in another submodule
504 * but when libyang parses such a module it adds the include into the main module so we are also done.
505 */
Radek Krejci62f0da72016-03-07 11:35:43 +0100506 }
507
508 return NULL;
509}
510
511API const struct lys_submodule *
Michal Vaskof6d94c62016-04-05 11:21:54 +0200512ly_ctx_get_submodule(const struct ly_ctx *ctx, const char *module, const char *revision, const char *submodule,
513 const char *sub_revision)
Radek Krejciefaeba32015-05-27 14:30:57 +0200514{
Radek Krejcie7973552016-03-07 08:12:01 +0100515 const struct lys_module *mainmod;
Michal Vaskof6d94c62016-04-05 11:21:54 +0200516 const struct lys_submodule *ret = NULL, *submod;
517 uint32_t idx = 0;
Radek Krejciefaeba32015-05-27 14:30:57 +0200518
Michal Vaskof6d94c62016-04-05 11:21:54 +0200519 if (!ctx || !submodule || (revision && !module)) {
Michal Vasko53b7da02018-02-13 15:28:42 +0100520 LOGARG;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200521 return NULL;
522 }
Radek Krejciefaeba32015-05-27 14:30:57 +0200523
Michal Vaskof6d94c62016-04-05 11:21:54 +0200524 while ((mainmod = ly_ctx_get_module_iter(ctx, &idx))) {
525 if (module && strcmp(mainmod->name, module)) {
526 /* main module name does not match */
527 continue;
528 }
529
530 if (revision && (!mainmod->rev || strcmp(revision, mainmod->rev[0].date))) {
531 /* main module revision does not match */
532 continue;
533 }
534
535 submod = ly_ctx_get_submodule2(mainmod, submodule);
536 if (!submod) {
537 continue;
538 }
539
540 if (!sub_revision) {
541 /* store only if newer */
542 if (ret) {
543 if (submod->rev && (!ret->rev || (strcmp(submod->rev[0].date, ret->rev[0].date) > 0))) {
544 ret = submod;
545 }
546 } else {
547 ret = submod;
548 }
549 } else {
550 /* store only if revision matches, we are done if it does */
551 if (!submod->rev) {
552 continue;
553 } else if (!strcmp(sub_revision, submod->rev[0].date)) {
554 ret = submod;
555 break;
556 }
557 }
Radek Krejcia7533f22016-03-07 07:37:45 +0100558 }
Radek Krejcic071c542016-01-27 14:57:51 +0100559
Michal Vaskof6d94c62016-04-05 11:21:54 +0200560 return ret;
Radek Krejciefaeba32015-05-27 14:30:57 +0200561}
562
Michal Vasko1e62a092015-12-01 12:27:20 +0100563static const struct lys_module *
Michal Vasko53b7da02018-02-13 15:28:42 +0100564ly_ctx_get_module_by(const struct ly_ctx *ctx, const char *key, size_t key_len, int offset, const char *revision,
565 int with_disabled, int implemented)
Radek Krejciefaeba32015-05-27 14:30:57 +0200566{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200567 int i;
Michal Vasko53b7da02018-02-13 15:28:42 +0100568 char *val;
Radek Krejcib8048692015-08-05 13:36:34 +0200569 struct lys_module *result = NULL;
Radek Krejciefaeba32015-05-27 14:30:57 +0200570
Radek Krejcifd4e6e32015-08-10 15:00:51 +0200571 if (!ctx || !key) {
Michal Vasko53b7da02018-02-13 15:28:42 +0100572 LOGARG;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200573 return NULL;
574 }
Radek Krejciefaeba32015-05-27 14:30:57 +0200575
Radek Krejcidce51452015-06-16 15:20:08 +0200576 for (i = 0; i < ctx->models.used; i++) {
Radek Krejci0ec51da2016-12-14 16:42:03 +0100577 if (!with_disabled && ctx->models.list[i]->disabled) {
578 /* skip the disabled modules */
579 continue;
580 }
Radek Krejcifd4e6e32015-08-10 15:00:51 +0200581 /* use offset to get address of the pointer to string (char**), remember that offset is in
582 * bytes, so we have to cast the pointer to the module to (char*), finally, we want to have
583 * string not the pointer to string
584 */
Michal Vasko53b7da02018-02-13 15:28:42 +0100585 val = *(char **)(((char *)ctx->models.list[i]) + offset);
586 if (!ctx->models.list[i] || (!key_len && strcmp(key, val)) || (key_len && (strncmp(key, val, key_len) || val[key_len]))) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200587 continue;
588 }
Radek Krejciefaeba32015-05-27 14:30:57 +0200589
Radek Krejcif647e612015-07-30 11:36:07 +0200590 if (!revision) {
591 /* compare revisons and remember the newest one */
592 if (result) {
593 if (!ctx->models.list[i]->rev_size) {
594 /* the current have no revision, keep the previous with some revision */
595 continue;
596 }
597 if (result->rev_size && strcmp(ctx->models.list[i]->rev[0].date, result->rev[0].date) < 0) {
598 /* the previous found matching module has a newer revision */
599 continue;
600 }
601 }
Radek Krejcidfb00d62017-09-06 09:39:35 +0200602 if (implemented) {
603 if (ctx->models.list[i]->implemented) {
604 /* we have the implemented revision */
605 result = ctx->models.list[i];
606 break;
607 } else {
608 /* do not remember the result, we are supposed to return the implemented revision
609 * not the newest one */
610 continue;
611 }
612 }
Radek Krejcif647e612015-07-30 11:36:07 +0200613
614 /* remember the current match and search for newer version */
615 result = ctx->models.list[i];
616 } else {
617 if (ctx->models.list[i]->rev_size && !strcmp(revision, ctx->models.list[i]->rev[0].date)) {
618 /* matching revision */
Michal Vasko97586502015-08-12 14:32:18 +0200619 result = ctx->models.list[i];
620 break;
Radek Krejcif647e612015-07-30 11:36:07 +0200621 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200622 }
623 }
Radek Krejciefaeba32015-05-27 14:30:57 +0200624
Radek Krejcif647e612015-07-30 11:36:07 +0200625 return result;
Radek Krejcifd4e6e32015-08-10 15:00:51 +0200626
627}
628
Michal Vasko1e62a092015-12-01 12:27:20 +0100629API const struct lys_module *
Radek Krejcidfb00d62017-09-06 09:39:35 +0200630ly_ctx_get_module_by_ns(const struct ly_ctx *ctx, const char *ns, const char *revision, int implemented)
Radek Krejcifd4e6e32015-08-10 15:00:51 +0200631{
Michal Vasko53b7da02018-02-13 15:28:42 +0100632 return ly_ctx_get_module_by(ctx, ns, 0, offsetof(struct lys_module, ns), revision, 0, implemented);
Radek Krejcifd4e6e32015-08-10 15:00:51 +0200633}
634
Michal Vasko1e62a092015-12-01 12:27:20 +0100635API const struct lys_module *
Radek Krejcidfb00d62017-09-06 09:39:35 +0200636ly_ctx_get_module(const struct ly_ctx *ctx, const char *name, const char *revision, int implemented)
Radek Krejcifd4e6e32015-08-10 15:00:51 +0200637{
Michal Vasko53b7da02018-02-13 15:28:42 +0100638 return ly_ctx_get_module_by(ctx, name, 0, offsetof(struct lys_module, name), revision, 0, implemented);
639}
640
641const struct lys_module *
642ly_ctx_nget_module(const struct ly_ctx *ctx, const char *name, size_t name_len, const char *revision, int implemented)
643{
644 return ly_ctx_get_module_by(ctx, name, name_len, offsetof(struct lys_module, name), revision, 0, implemented);
Radek Krejcida04f4a2015-05-21 12:54:09 +0200645}
Michal Vasko3ec07dc2015-06-30 15:51:30 +0200646
Radek Krejci21601a32016-03-07 11:39:27 +0100647API const struct lys_module *
648ly_ctx_get_module_older(const struct ly_ctx *ctx, const struct lys_module *module)
649{
650 int i;
651 const struct lys_module *result = NULL, *iter;
652
653 if (!ctx || !module || !module->rev_size) {
Michal Vasko53b7da02018-02-13 15:28:42 +0100654 LOGARG;
Radek Krejci21601a32016-03-07 11:39:27 +0100655 return NULL;
656 }
657
658
659 for (i = 0; i < ctx->models.used; i++) {
660 iter = ctx->models.list[i];
Radek Krejci0ec51da2016-12-14 16:42:03 +0100661 if (iter->disabled) {
662 /* skip the disabled modules */
663 continue;
664 }
Radek Krejci21601a32016-03-07 11:39:27 +0100665 if (iter == module || !iter->rev_size) {
666 /* iter is the module itself or iter has no revision */
667 continue;
668 }
669 if (!ly_strequal(module->name, iter->name, 0)) {
670 /* different module */
671 continue;
672 }
673 if (strcmp(iter->rev[0].date, module->rev[0].date) < 0) {
674 /* iter is older than module */
675 if (result) {
676 if (strcmp(iter->rev[0].date, result->rev[0].date) > 0) {
677 /* iter is newer than current result */
678 result = iter;
679 }
680 } else {
681 result = iter;
682 }
683 }
684 }
685
686 return result;
687}
688
Michal Vasko99b0aad2015-12-01 12:28:51 +0100689API void
Michal Vaskoca28aab2017-01-13 13:50:12 +0100690ly_ctx_set_module_imp_clb(struct ly_ctx *ctx, ly_module_imp_clb clb, void *user_data)
Michal Vasko82465962015-11-10 11:03:11 +0100691{
Michal Vaskoad9f92a2017-04-06 09:49:07 +0200692 if (!ctx) {
Michal Vasko53b7da02018-02-13 15:28:42 +0100693 LOGARG;
Michal Vaskoad9f92a2017-04-06 09:49:07 +0200694 return;
695 }
696
Michal Vaskof53187d2017-01-13 13:23:14 +0100697 ctx->imp_clb = clb;
698 ctx->imp_clb_data = user_data;
Michal Vasko99b0aad2015-12-01 12:28:51 +0100699}
700
Michal Vaskof53187d2017-01-13 13:23:14 +0100701API ly_module_imp_clb
Michal Vaskoca28aab2017-01-13 13:50:12 +0100702ly_ctx_get_module_imp_clb(const struct ly_ctx *ctx, void **user_data)
Michal Vasko99b0aad2015-12-01 12:28:51 +0100703{
Radek Krejciee554172016-12-14 10:29:06 +0100704 if (!ctx) {
Michal Vasko53b7da02018-02-13 15:28:42 +0100705 LOGARG;
Radek Krejciee554172016-12-14 10:29:06 +0100706 return NULL;
707 }
708
Michal Vasko99b0aad2015-12-01 12:28:51 +0100709 if (user_data) {
Michal Vaskof53187d2017-01-13 13:23:14 +0100710 *user_data = ctx->imp_clb_data;
Michal Vasko99b0aad2015-12-01 12:28:51 +0100711 }
Michal Vaskof53187d2017-01-13 13:23:14 +0100712 return ctx->imp_clb;
713}
714
715API void
Michal Vaskoca28aab2017-01-13 13:50:12 +0100716ly_ctx_set_module_data_clb(struct ly_ctx *ctx, ly_module_data_clb clb, void *user_data)
Michal Vaskof53187d2017-01-13 13:23:14 +0100717{
Michal Vaskoad9f92a2017-04-06 09:49:07 +0200718 if (!ctx) {
Michal Vasko53b7da02018-02-13 15:28:42 +0100719 LOGARG;
Michal Vaskoad9f92a2017-04-06 09:49:07 +0200720 return;
721 }
722
Michal Vaskof53187d2017-01-13 13:23:14 +0100723 ctx->data_clb = clb;
724 ctx->data_clb_data = user_data;
725}
726
727API ly_module_data_clb
Michal Vaskoca28aab2017-01-13 13:50:12 +0100728ly_ctx_get_module_data_clb(const struct ly_ctx *ctx, void **user_data)
Michal Vaskof53187d2017-01-13 13:23:14 +0100729{
Michal Vaskoad9f92a2017-04-06 09:49:07 +0200730 if (!ctx) {
Michal Vasko53b7da02018-02-13 15:28:42 +0100731 LOGARG;
Michal Vaskoad9f92a2017-04-06 09:49:07 +0200732 return NULL;
733 }
734
Michal Vaskof53187d2017-01-13 13:23:14 +0100735 if (user_data) {
736 *user_data = ctx->data_clb_data;
737 }
738 return ctx->data_clb;
Michal Vasko99b0aad2015-12-01 12:28:51 +0100739}
740
Radek Krejcibf4e4652016-10-21 15:44:13 +0200741const struct lys_module *
Michal Vasko84475152016-07-25 16:16:25 +0200742ly_ctx_load_sub_module(struct ly_ctx *ctx, struct lys_module *module, const char *name, const char *revision,
Michal Vasko58e5f3e2016-07-28 11:06:34 +0200743 int implement, struct unres_schema *unres)
Michal Vasko99b0aad2015-12-01 12:28:51 +0100744{
Michal Vasko8f3160e2017-09-27 11:25:26 +0200745 struct lys_module *mod;
746 char *module_data = NULL;
Radek Krejci03203412016-06-23 15:20:53 +0200747 int i;
Michal Vaskod3e975b2016-03-03 15:40:21 +0100748 void (*module_data_free)(void *module_data) = NULL;
Michal Vasko99b0aad2015-12-01 12:28:51 +0100749 LYS_INFORMAT format = LYS_IN_UNKNOWN;
Michal Vasko82465962015-11-10 11:03:11 +0100750
Michal Vasko84475152016-07-25 16:16:25 +0200751 if (!module) {
Radek Krejcibf4e4652016-10-21 15:44:13 +0200752 /* exception for internal modules */
Radek Krejcidfb00d62017-09-06 09:39:35 +0200753 for (i = 0; i < ctx->internal_module_count; i++) {
Michal Vasko84475152016-07-25 16:16:25 +0200754 if (ly_strequal(name, internal_modules[i].name, 0)) {
755 if (!revision || ly_strequal(revision, internal_modules[i].revision, 0)) {
756 /* return internal module */
Radek Krejcidfb00d62017-09-06 09:39:35 +0200757 return (struct lys_module *)ly_ctx_get_module(ctx, name, revision, 0);
Michal Vasko84475152016-07-25 16:16:25 +0200758 }
Radek Krejci03203412016-06-23 15:20:53 +0200759 }
760 }
Michal Vasko8f3160e2017-09-27 11:25:26 +0200761 /* try to get the schema from the context (with or without revision),
762 * include the disabled modules in the search to avoid their duplication,
763 * they are enabled by the subsequent call to lys_set_implemented() */
764 for (i = ctx->internal_module_count, mod = NULL; i < ctx->models.used; i++) {
765 mod = ctx->models.list[i]; /* shortcut */
766 if (ly_strequal(name, mod->name, 0)) {
767 if (revision && mod->rev_size && !strcmp(revision, mod->rev[0].date)) {
768 /* the specific revision was already loaded */
769 break;
770 } else if (!revision && mod->latest_revision) {
771 /* the latest revision of this module was already loaded */
Radek Krejci0ec51da2016-12-14 16:42:03 +0100772 break;
Radek Krejci44564912017-10-31 16:49:29 +0100773 } else if (implement && mod->implemented && !revision) {
774 /* we are not able to implement another module, so consider this module as the latest one */
775 break;
Radek Krejci0ec51da2016-12-14 16:42:03 +0100776 }
Michal Vasko8f3160e2017-09-27 11:25:26 +0200777 }
778 mod = NULL;
779 }
780 if (mod) {
781 /* module must be enabled */
782 if (mod->disabled) {
783 lys_set_enabled(mod);
784 }
785 /* module is supposed to be implemented */
786 if (implement && lys_set_implemented(mod)) {
787 /* the schema cannot be implemented */
Radek Krejci0ec51da2016-12-14 16:42:03 +0100788 mod = NULL;
789 }
Michal Vasko8f3160e2017-09-27 11:25:26 +0200790 return mod;
Radek Krejcibf4e4652016-10-21 15:44:13 +0200791 }
Radek Krejci03203412016-06-23 15:20:53 +0200792 }
793
Michal Vasko8f3160e2017-09-27 11:25:26 +0200794 /* module is not yet in context, use the user callback or try to find the schema on our own */
Michal Vaskof53187d2017-01-13 13:23:14 +0100795 if (ctx->imp_clb) {
Michal Vasko8f3160e2017-09-27 11:25:26 +0200796 ly_errno = LY_SUCCESS;
Michal Vasko84475152016-07-25 16:16:25 +0200797 if (module) {
798 mod = lys_main_module(module);
Michal Vaskof53187d2017-01-13 13:23:14 +0100799 module_data = ctx->imp_clb(mod->name, (mod->rev_size ? mod->rev[0].date : NULL), name, revision, ctx->imp_clb_data, &format, &module_data_free);
Michal Vasko84475152016-07-25 16:16:25 +0200800 } else {
Michal Vaskof53187d2017-01-13 13:23:14 +0100801 module_data = ctx->imp_clb(name, revision, NULL, NULL, ctx->imp_clb_data, &format, &module_data_free);
Michal Vasko84475152016-07-25 16:16:25 +0200802 }
Michal Vasko8f3160e2017-09-27 11:25:26 +0200803 if (!module_data && (ly_errno != LY_SUCCESS)) {
804 /* callback encountered an error, do not change it */
Michal Vasko53b7da02018-02-13 15:28:42 +0100805 LOGERR(ctx, ly_errno, "User module retrieval callback failed!");
Michal Vasko8f3160e2017-09-27 11:25:26 +0200806 return NULL;
Michal Vasko82465962015-11-10 11:03:11 +0100807 }
Michal Vasko8f3160e2017-09-27 11:25:26 +0200808 }
Michal Vasko84475152016-07-25 16:16:25 +0200809
Michal Vasko8f3160e2017-09-27 11:25:26 +0200810 if (module_data) {
811 /* we got the module from the callback */
Michal Vasko84475152016-07-25 16:16:25 +0200812 if (module) {
Michal Vasko5b998712017-01-26 10:34:06 +0100813 mod = (struct lys_module *)lys_sub_parse_mem(module, module_data, format, unres);
Michal Vasko84475152016-07-25 16:16:25 +0200814 } else {
Michal Vaskofb98dc42018-01-11 13:38:28 +0100815 mod = (struct lys_module *)lys_parse_mem_(ctx, module_data, format, NULL, 0, implement);
Michal Vasko84475152016-07-25 16:16:25 +0200816 }
817
Michal Vasko99b0aad2015-12-01 12:28:51 +0100818 if (module_data_free) {
819 module_data_free(module_data);
Michal Vasko82465962015-11-10 11:03:11 +0100820 }
Michal Vasko99b0aad2015-12-01 12:28:51 +0100821 } else {
Michal Vasko8f3160e2017-09-27 11:25:26 +0200822 /* module was not received from the callback or there is no callback set */
Michal Vasko58e5f3e2016-07-28 11:06:34 +0200823 mod = lyp_search_file(ctx, module, name, revision, implement, unres);
Michal Vasko82465962015-11-10 11:03:11 +0100824 }
825
Michal Vasko8f3160e2017-09-27 11:25:26 +0200826#ifdef LY_ENABLED_LATEST_REVISIONS
827 if (!revision && mod) {
828 /* module is the latest revision found */
829 mod->latest_revision = 1;
830 }
831#endif
832
Michal Vasko84475152016-07-25 16:16:25 +0200833 return mod;
834}
835
836API const struct lys_module *
837ly_ctx_load_module(struct ly_ctx *ctx, const char *name, const char *revision)
838{
839 if (!ctx || !name) {
Michal Vasko53b7da02018-02-13 15:28:42 +0100840 LOGARG;
Michal Vasko84475152016-07-25 16:16:25 +0200841 return NULL;
842 }
843
Michal Vasko53b7da02018-02-13 15:28:42 +0100844 return ly_ctx_load_sub_module(ctx, NULL, name, revision && revision[0] ? revision : NULL, 1, NULL);
Michal Vasko82465962015-11-10 11:03:11 +0100845}
846
Radek Krejci85a54be2016-10-20 12:39:56 +0200847/*
848 * mods - set of removed modules, if NULL all modules are supposed to be removed so any backlink is invalid
849 */
Michal Vasko4be5fa22017-02-07 10:12:32 +0100850static void
851ctx_modules_undo_backlinks(struct ly_ctx *ctx, struct ly_set *mods)
Radek Krejci85a54be2016-10-20 12:39:56 +0200852{
853 int o;
854 uint8_t j;
855 unsigned int u, v;
856 struct lys_module *mod;
857 struct lys_node *elem, *next;
858 struct lys_node_leaf *leaf;
859
860 /* maintain backlinks (start with internal ietf-yang-library which have leafs as possible targets of leafrefs */
Radek Krejcidfb00d62017-09-06 09:39:35 +0200861 for (o = ctx->internal_module_count - 1; o < ctx->models.used; o++) {
Radek Krejci85a54be2016-10-20 12:39:56 +0200862 mod = ctx->models.list[o]; /* shortcut */
863
864 /* 1) features */
865 for (j = 0; j < mod->features_size; j++) {
866 if (!mod->features[j].depfeatures) {
867 continue;
868 }
869 for (v = 0; v < mod->features[j].depfeatures->number; v++) {
870 if (!mods || ly_set_contains(mods, ((struct lys_feature *)mod->features[j].depfeatures->set.g[v])->module) != -1) {
871 /* depending feature is in module to remove */
872 ly_set_rm_index(mod->features[j].depfeatures, v);
873 v--;
874 }
875 }
876 if (!mod->features[j].depfeatures->number) {
877 /* all backlinks removed */
878 ly_set_free(mod->features[j].depfeatures);
879 mod->features[j].depfeatures = NULL;
880 }
881 }
Michal Vasko4be5fa22017-02-07 10:12:32 +0100882
883 /* 2) identities */
Radek Krejci85a54be2016-10-20 12:39:56 +0200884 for (u = 0; u < mod->ident_size; u++) {
885 if (!mod->ident[u].der) {
886 continue;
887 }
888 for (v = 0; v < mod->ident[u].der->number; v++) {
889 if (!mods || ly_set_contains(mods, ((struct lys_ident *)mod->ident[u].der->set.g[v])->module) != -1) {
890 /* derived identity is in module to remove */
891 ly_set_rm_index(mod->ident[u].der, v);
892 v--;
893 }
894 }
895 if (!mod->ident[u].der->number) {
896 /* all backlinks removed */
897 ly_set_free(mod->ident[u].der);
898 mod->ident[u].der = NULL;
899 }
900 }
901
Michal Vasko4be5fa22017-02-07 10:12:32 +0100902 /* 3) leafrefs */
Radek Krejci85a54be2016-10-20 12:39:56 +0200903 for (elem = next = mod->data; elem; elem = next) {
904 if (elem->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
905 leaf = (struct lys_node_leaf *)elem; /* shortcut */
906 if (leaf->backlinks) {
907 if (!mods) {
908 /* remove all backlinks */
909 ly_set_free(leaf->backlinks);
910 leaf->backlinks = NULL;
911 } else {
912 for (v = 0; v < leaf->backlinks->number; v++) {
913 if (ly_set_contains(mods, leaf->backlinks->set.s[v]->module) != -1) {
914 /* derived identity is in module to remove */
915 ly_set_rm_index(leaf->backlinks, v);
916 v--;
917 }
918 }
919 if (!leaf->backlinks->number) {
920 /* all backlinks removed */
921 ly_set_free(leaf->backlinks);
922 leaf->backlinks = NULL;
923 }
924 }
925 }
926 }
927
928 /* select next element to process */
929 next = elem->child;
930 /* child exception for leafs, leaflists, anyxml and groupings */
931 if (elem->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA | LYS_GROUPING)) {
932 next = NULL;
933 }
934 if (!next) {
935 /* no children, try siblings */
936 next = elem->next;
937 }
938 while (!next) {
939 /* parent is already processed, go to its sibling */
940 elem = lys_parent(elem);
941 if (!elem) {
942 /* we are done, no next element to process */
943 break;
944 }
945 /* no siblings, go back through parents */
946 next = elem->next;
947 }
948 }
949 }
Michal Vasko4be5fa22017-02-07 10:12:32 +0100950}
Radek Krejci85a54be2016-10-20 12:39:56 +0200951
Michal Vasko4be5fa22017-02-07 10:12:32 +0100952static int
Radek Krejci83a4bac2017-02-07 15:53:04 +0100953ctx_modules_redo_backlinks(struct ly_set *mods)
Michal Vasko4be5fa22017-02-07 10:12:32 +0100954{
Radek Krejci83a4bac2017-02-07 15:53:04 +0100955 unsigned int i, j, k, s;
956 struct lys_module *mod;
957 struct lys_node *next, *elem;
958 struct lys_type *type;
959 struct lys_feature *feat;
Michal Vasko4be5fa22017-02-07 10:12:32 +0100960
Michal Vasko4be5fa22017-02-07 10:12:32 +0100961 for (i = 0; i < mods->number; ++i) {
Radek Krejci83a4bac2017-02-07 15:53:04 +0100962 mod = (struct lys_module *)mods->set.g[i]; /* shortcut */
Michal Vasko4be5fa22017-02-07 10:12:32 +0100963
Radek Krejci83a4bac2017-02-07 15:53:04 +0100964 /* identities */
Radek Krejci9e6af732017-04-27 14:40:25 +0200965 if (mod->implemented) {
966 for (j = 0; j < mod->ident_size; j++) {
967 for (k = 0; k < mod->ident[j].base_size; k++) {
968 resolve_identity_backlink_update(&mod->ident[j], mod->ident[j].base[k]);
969 }
Radek Krejci83a4bac2017-02-07 15:53:04 +0100970 }
971 }
Michal Vasko4be5fa22017-02-07 10:12:32 +0100972
Radek Krejci83a4bac2017-02-07 15:53:04 +0100973 /* features */
974 for (j = 0; j < mod->features_size; j++) {
975 for (k = 0; k < mod->features[j].iffeature_size; k++) {
976 resolve_iffeature_getsizes(&mod->features[j].iffeature[k], NULL, &s);
977 while (s--) {
978 feat = mod->features[j].iffeature[k].features[s]; /* shortcut */
979 if (!feat->depfeatures) {
980 feat->depfeatures = ly_set_new();
981 }
982 ly_set_add(feat->depfeatures, &mod->features[j], LY_SET_OPT_USEASLIST);
983 }
984 }
985 }
986
987 /* leafrefs */
988 LY_TREE_DFS_BEGIN(mod->data, next, elem) {
Michal Vaskofa3d2f72017-04-10 13:30:44 +0200989 if (elem->nodetype == LYS_GROUPING) {
990 goto next_sibling;
991 }
992
Radek Krejci83a4bac2017-02-07 15:53:04 +0100993 if (elem->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
994 type = &((struct lys_node_leaf *)elem)->type; /* shortcut */
995 if (type->base == LY_TYPE_LEAFREF) {
996 lys_leaf_add_leafref_target(type->info.lref.target, elem);
997 }
998 }
999
Michal Vaskofa3d2f72017-04-10 13:30:44 +02001000 /* select element for the next run - children first */
1001 next = elem->child;
1002
1003 /* child exception for leafs, leaflists and anyxml without children */
1004 if (elem->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
1005 next = NULL;
1006 }
1007 if (!next) {
1008next_sibling:
1009 /* no children */
1010 if (elem == mod->data) {
1011 /* we are done, (START) has no children */
1012 break;
1013 }
1014 /* try siblings */
1015 next = elem->next;
1016 }
1017 while (!next) {
1018 /* parent is already processed, go to its sibling */
1019 elem = lys_parent(elem);
1020
1021 /* no siblings, go back through parents */
1022 if (lys_parent(elem) == lys_parent(mod->data)) {
1023 /* we are done, no next element to process */
1024 break;
1025 }
1026 next = elem->next;
1027 }
Radek Krejci83a4bac2017-02-07 15:53:04 +01001028 }
Michal Vasko4be5fa22017-02-07 10:12:32 +01001029 }
1030
1031 return 0;
Radek Krejci85a54be2016-10-20 12:39:56 +02001032}
1033
Radek Krejci8c107fe2016-10-17 16:00:18 +02001034API int
Radek Krejci0ec51da2016-12-14 16:42:03 +01001035lys_set_disabled(const struct lys_module *module)
1036{
1037 struct ly_ctx *ctx; /* shortcut */
1038 struct lys_module *mod;
1039 struct ly_set *mods;
1040 uint8_t j, imported;
1041 int i, o;
Radek Krejci29eac3d2017-06-01 16:50:02 +02001042 unsigned int u, v;
Radek Krejci0ec51da2016-12-14 16:42:03 +01001043
1044 if (!module) {
Michal Vasko53b7da02018-02-13 15:28:42 +01001045 LOGARG;
Radek Krejci0ec51da2016-12-14 16:42:03 +01001046 return EXIT_FAILURE;
1047 } else if (module->disabled) {
1048 /* already disabled module */
1049 return EXIT_SUCCESS;
1050 }
1051 mod = (struct lys_module *)module;
1052 ctx = mod->ctx;
1053
1054 /* avoid disabling internal modules */
Radek Krejcidfb00d62017-09-06 09:39:35 +02001055 for (i = 0; i < ctx->internal_module_count; i++) {
Radek Krejci0ec51da2016-12-14 16:42:03 +01001056 if (mod == ctx->models.list[i]) {
Michal Vasko53b7da02018-02-13 15:28:42 +01001057 LOGERR(ctx, LY_EINVAL, "Internal module \"%s\" cannot be disabled.", mod->name);
Radek Krejci0ec51da2016-12-14 16:42:03 +01001058 return EXIT_FAILURE;
1059 }
1060 }
1061
1062 /* disable the module */
1063 mod->disabled = 1;
1064
1065 /* get the complete list of modules to disable because of dependencies,
1066 * we are going also to disable all the imported (not implemented) modules
1067 * that are not used in any other module */
1068 mods = ly_set_new();
1069 ly_set_add(mods, mod, 0);
1070checkdependency:
Radek Krejcidfb00d62017-09-06 09:39:35 +02001071 for (i = ctx->internal_module_count; i < ctx->models.used; i++) {
Radek Krejci0ec51da2016-12-14 16:42:03 +01001072 mod = ctx->models.list[i]; /* shortcut */
1073 if (mod->disabled) {
1074 /* skip the already disabled modules */
1075 continue;
1076 }
1077
1078 /* check depndency of imported modules */
1079 for (j = 0; j < mod->imp_size; j++) {
1080 for (u = 0; u < mods->number; u++) {
1081 if (mod->imp[j].module == mods->set.g[u]) {
1082 /* module is importing some module to disable, so it must be also disabled */
1083 mod->disabled = 1;
1084 ly_set_add(mods, mod, 0);
1085 /* we have to start again because some of the already checked modules can
1086 * depend on the one we have just decided to disable */
1087 goto checkdependency;
1088 }
1089 }
1090 }
1091 /* check if the imported module is used in any module supposed to be kept */
1092 if (!mod->implemented) {
1093 imported = 0;
Radek Krejcidfb00d62017-09-06 09:39:35 +02001094 for (o = ctx->internal_module_count; o < ctx->models.used; o++) {
Radek Krejci0ec51da2016-12-14 16:42:03 +01001095 if (ctx->models.list[o]->disabled) {
1096 /* skip modules already disabled */
1097 continue;
1098 }
1099 for (j = 0; j < ctx->models.list[o]->imp_size; j++) {
1100 if (ctx->models.list[o]->imp[j].module == mod) {
1101 /* the module is used in some other module not yet selected to be disabled */
1102 imported = 1;
1103 goto imported;
1104 }
1105 }
1106 }
1107imported:
1108 if (!imported) {
1109 /* module is not implemented and neither imported by any other module in context
1110 * which is supposed to be kept enabled after this operation, so we are going to disable also
1111 * this module */
1112 mod->disabled = 1;
1113 ly_set_add(mods, mod, 0);
1114 /* we have to start again, this time not because other module can depend on this one
1115 * (we know that there is no such module), but because the module can import module
1116 * that could became useless. If there are no imports, we can continue */
1117 if (mod->imp_size) {
1118 goto checkdependency;
1119 }
1120 }
1121 }
1122 }
1123
1124 /* before removing applied deviations, augments and updating leafrefs, we have to enable the modules
1125 * to disable to allow all that operations */
1126 for (u = 0; u < mods->number; u++) {
1127 ((struct lys_module *)mods->set.g[u])->disabled = 0;
1128 }
1129
1130 /* maintain backlinks (start with internal ietf-yang-library which have leafs as possible targets of leafrefs */
Michal Vasko4be5fa22017-02-07 10:12:32 +01001131 ctx_modules_undo_backlinks(ctx, mods);
Radek Krejci0ec51da2016-12-14 16:42:03 +01001132
1133 /* remove the applied deviations and augments */
1134 for (u = 0; u < mods->number; u++) {
1135 lys_sub_module_remove_devs_augs((struct lys_module *)mods->set.g[u]);
1136 }
1137
Radek Krejci29eac3d2017-06-01 16:50:02 +02001138 /* now again disable the modules to disable and disable also all its submodules */
Radek Krejci0ec51da2016-12-14 16:42:03 +01001139 for (u = 0; u < mods->number; u++) {
Radek Krejci29eac3d2017-06-01 16:50:02 +02001140 mod = (struct lys_module *)mods->set.g[u];
1141 mod->disabled = 1;
1142 for (v = 0; v < mod->inc_size; v++) {
1143 mod->inc[v].submodule->disabled = 1;
1144 }
Radek Krejci0ec51da2016-12-14 16:42:03 +01001145 }
1146
1147 /* free the set */
1148 ly_set_free(mods);
1149
1150 /* update the module-set-id */
1151 ctx->models.module_set_id++;
1152
1153 return EXIT_SUCCESS;
1154}
1155
1156static void
1157lys_set_enabled_(struct ly_set *mods, struct lys_module *mod)
1158{
1159 unsigned int i;
1160
1161 ly_set_add(mods, mod, 0);
1162 mod->disabled = 0;
1163
Radek Krejci29eac3d2017-06-01 16:50:02 +02001164 for (i = 0; i < mod->inc_size; i++) {
1165 mod->inc[i].submodule->disabled = 0;
1166 }
1167
Radek Krejci0ec51da2016-12-14 16:42:03 +01001168 /* go recursively */
1169 for (i = 0; i < mod->imp_size; i++) {
1170 if (!mod->imp[i].module->disabled) {
1171 continue;
1172 }
1173
1174 lys_set_enabled_(mods, mod->imp[i].module);
1175 }
1176}
1177
1178API int
1179lys_set_enabled(const struct lys_module *module)
1180{
1181 struct ly_ctx *ctx; /* shortcut */
1182 struct lys_module *mod;
1183 struct ly_set *mods, *disabled;
1184 int i;
Radek Krejci29eac3d2017-06-01 16:50:02 +02001185 unsigned int u, v, w;
Radek Krejci0ec51da2016-12-14 16:42:03 +01001186
1187 if (!module) {
Michal Vasko53b7da02018-02-13 15:28:42 +01001188 LOGARG;
Radek Krejci0ec51da2016-12-14 16:42:03 +01001189 return EXIT_FAILURE;
1190 } else if (!module->disabled) {
1191 /* already enabled module */
1192 return EXIT_SUCCESS;
1193 }
1194 mod = (struct lys_module *)module;
1195 ctx = mod->ctx;
1196
1197 /* avoid disabling internal modules */
Radek Krejcidfb00d62017-09-06 09:39:35 +02001198 for (i = 0; i < ctx->internal_module_count; i++) {
Radek Krejci0ec51da2016-12-14 16:42:03 +01001199 if (mod == ctx->models.list[i]) {
Michal Vasko53b7da02018-02-13 15:28:42 +01001200 LOGERR(ctx, LY_EINVAL, "Internal module \"%s\" cannot be removed.", mod->name);
Radek Krejci0ec51da2016-12-14 16:42:03 +01001201 return EXIT_FAILURE;
1202 }
1203 }
1204
1205 mods = ly_set_new();
1206 disabled = ly_set_new();
1207
1208 /* enable the module, including its dependencies */
1209 lys_set_enabled_(mods, mod);
1210
1211 /* we will go through the all disabled modules in the context, if the module has no dependency (import)
1212 * that is still disabled AND at least one of its imported module is from the set we are enabling now,
1213 * it is going to be also enabled. This way we try to revert everething that was possibly done by
1214 * lys_set_disabled(). */
1215checkdependency:
Radek Krejcidfb00d62017-09-06 09:39:35 +02001216 for (i = ctx->internal_module_count; i < ctx->models.used; i++) {
Radek Krejci0ec51da2016-12-14 16:42:03 +01001217 mod = ctx->models.list[i]; /* shortcut */
1218 if (!mod->disabled || ly_set_contains(disabled, mod) != -1) {
1219 /* skip the enabled modules */
1220 continue;
1221 }
1222
1223 /* check imported modules */
1224 for (u = 0; u < mod->imp_size; u++) {
1225 if (mod->imp[u].module->disabled) {
1226 /* it has disabled dependency so it must stay disabled */
1227 break;
1228 }
1229 }
1230 if (u < mod->imp_size) {
1231 /* it has disabled dependency, continue with the next module in the context */
1232 continue;
1233 }
1234
1235 /* get know if at least one of the imported modules is being enabled this time */
1236 for (u = 0; u < mod->imp_size; u++) {
1237 for (v = 0; v < mods->number; v++) {
1238 if (mod->imp[u].module == mods->set.g[v]) {
1239 /* yes, it is, so they are connected and we are going to enable it as well,
1240 * it is not necessary to call recursive lys_set_enable_() because we already
1241 * know that there is no disabled import to enable */
1242 mod->disabled = 0;
1243 ly_set_add(mods, mod, 0);
Radek Krejci29eac3d2017-06-01 16:50:02 +02001244 for (w = 0; w < mod->inc_size; w++) {
1245 mod->inc[w].submodule->disabled = 0;
1246 }
Radek Krejci0ec51da2016-12-14 16:42:03 +01001247 /* we have to start again because some of the already checked modules can
1248 * depend on the one we have just decided to enable */
1249 goto checkdependency;
1250 }
1251 }
1252 }
1253
1254 /* this module is disabled, but it does not depend on any other disabled module and none
1255 * of its imports was not enabled in this call. No future enabling of the disabled module
1256 * will change this so we can remember the module and skip it next time we will have to go
1257 * through the all context because of the checkdependency goto.
1258 */
1259 ly_set_add(disabled, mod, 0);
1260 }
1261
1262 /* maintain backlinks (start with internal ietf-yang-library which have leafs as possible targets of leafrefs */
Radek Krejci83a4bac2017-02-07 15:53:04 +01001263 ctx_modules_redo_backlinks(mods);
Radek Krejci0ec51da2016-12-14 16:42:03 +01001264
1265 /* re-apply the deviations and augments */
1266 for (v = 0; v < mods->number; v++) {
1267 lys_sub_module_apply_devs_augs((struct lys_module *)mods->set.g[v]);
1268 }
1269
1270 /* free the sets */
1271 ly_set_free(mods);
1272 ly_set_free(disabled);
1273
1274 /* update the module-set-id */
1275 ctx->models.module_set_id++;
1276
1277 return EXIT_SUCCESS;
1278}
1279
1280API int
1281ly_ctx_remove_module(const struct lys_module *module,
Radek Krejci8c107fe2016-10-17 16:00:18 +02001282 void (*private_destructor)(const struct lys_node *node, void *priv))
1283{
Radek Krejci0ec51da2016-12-14 16:42:03 +01001284 struct ly_ctx *ctx; /* shortcut */
Radek Krejci8c107fe2016-10-17 16:00:18 +02001285 struct lys_module *mod = NULL;
1286 struct ly_set *mods;
1287 uint8_t j, imported;
1288 int i, o;
1289 unsigned int u;
1290
Radek Krejci0ec51da2016-12-14 16:42:03 +01001291 if (!module) {
Michal Vasko53b7da02018-02-13 15:28:42 +01001292 LOGARG;
Radek Krejci8c107fe2016-10-17 16:00:18 +02001293 return EXIT_FAILURE;
1294 }
1295
Radek Krejci0ec51da2016-12-14 16:42:03 +01001296 mod = (struct lys_module *)module;
1297 ctx = mod->ctx;
1298
Radek Krejci8c107fe2016-10-17 16:00:18 +02001299 /* avoid removing internal modules ... */
Radek Krejcidfb00d62017-09-06 09:39:35 +02001300 for (i = 0; i < ctx->internal_module_count; i++) {
Radek Krejci8c107fe2016-10-17 16:00:18 +02001301 if (mod == ctx->models.list[i]) {
Michal Vasko53b7da02018-02-13 15:28:42 +01001302 LOGERR(ctx, LY_EINVAL, "Internal module \"%s\" cannot be removed.", mod->name);
Radek Krejci8c107fe2016-10-17 16:00:18 +02001303 return EXIT_FAILURE;
1304 }
1305 }
1306 /* ... and hide the module from the further processing of the context modules list */
Radek Krejcidfb00d62017-09-06 09:39:35 +02001307 for (i = ctx->internal_module_count; i < ctx->models.used; i++) {
Radek Krejci8c107fe2016-10-17 16:00:18 +02001308 if (mod == ctx->models.list[i]) {
1309 ctx->models.list[i] = NULL;
1310 break;
1311 }
1312 }
1313
1314 /* get the complete list of modules to remove because of dependencies,
1315 * we are going also to remove all the imported (not implemented) modules
1316 * that are not used in any other module */
1317 mods = ly_set_new();
1318 ly_set_add(mods, mod, 0);
1319checkdependency:
Radek Krejcidfb00d62017-09-06 09:39:35 +02001320 for (i = ctx->internal_module_count; i < ctx->models.used; i++) {
Radek Krejci8c107fe2016-10-17 16:00:18 +02001321 mod = ctx->models.list[i]; /* shortcut */
1322 if (!mod) {
1323 /* skip modules already selected for removing */
1324 continue;
1325 }
1326
1327 /* check depndency of imported modules */
1328 for (j = 0; j < mod->imp_size; j++) {
1329 for (u = 0; u < mods->number; u++) {
1330 if (mod->imp[j].module == mods->set.g[u]) {
1331 /* module is importing some module to remove, so it must be also removed */
1332 ly_set_add(mods, mod, 0);
1333 ctx->models.list[i] = NULL;
1334 /* we have to start again because some of the already checked modules can
1335 * depend on the one we have just decided to remove */
1336 goto checkdependency;
1337 }
1338 }
1339 }
1340 /* check if the imported module is used in any module supposed to be kept */
1341 if (!mod->implemented) {
1342 imported = 0;
Radek Krejcidfb00d62017-09-06 09:39:35 +02001343 for (o = ctx->internal_module_count; o < ctx->models.used; o++) {
Radek Krejci8c107fe2016-10-17 16:00:18 +02001344 if (!ctx->models.list[o]) {
1345 /* skip modules already selected for removing */
1346 continue;
1347 }
1348 for (j = 0; j < ctx->models.list[o]->imp_size; j++) {
1349 if (ctx->models.list[o]->imp[j].module == mod) {
1350 /* the module is used in some other module not yet selected to be deleted */
1351 imported = 1;
1352 goto imported;
1353 }
1354 }
1355 }
1356imported:
1357 if (!imported) {
1358 /* module is not implemented and neither imported by any other module in context
1359 * which is supposed to be kept after this operation, so we are going to remove also
1360 * this useless module */
1361 ly_set_add(mods, mod, 0);
1362 ctx->models.list[i] = NULL;
1363 /* we have to start again, this time not because other module can depend on this one
Radek Krejci0ec51da2016-12-14 16:42:03 +01001364 * (we know that there is no such module), but because the module can import module
Radek Krejci8c107fe2016-10-17 16:00:18 +02001365 * that could became useless. If there are no imports, we can continue */
1366 if (mod->imp_size) {
1367 goto checkdependency;
1368 }
1369 }
1370 }
1371 }
1372
Radek Krejci8c107fe2016-10-17 16:00:18 +02001373
1374 /* consolidate the modules list */
Radek Krejcidfb00d62017-09-06 09:39:35 +02001375 for (i = o = ctx->internal_module_count; i < ctx->models.used; i++) {
Radek Krejci8c107fe2016-10-17 16:00:18 +02001376 if (ctx->models.list[o]) {
1377 /* used cell */
1378 o++;
1379 } else {
1380 /* the current output cell is empty, move here an input cell */
1381 ctx->models.list[o] = ctx->models.list[i];
1382 ctx->models.list[i] = NULL;
1383 }
1384 }
1385 /* get the last used cell to get know the number of used */
1386 while (!ctx->models.list[o]) {
1387 o--;
1388 }
1389 ctx->models.used = o + 1;
1390 ctx->models.module_set_id++;
1391
Radek Krejci85a54be2016-10-20 12:39:56 +02001392 /* maintain backlinks (start with internal ietf-yang-library which have leafs as possible targets of leafrefs */
Michal Vasko4be5fa22017-02-07 10:12:32 +01001393 ctx_modules_undo_backlinks(ctx, mods);
Radek Krejci85a54be2016-10-20 12:39:56 +02001394
1395 /* free the modules */
1396 for (u = 0; u < mods->number; u++) {
Radek Krejcib2541a32016-12-12 16:45:57 +01001397 /* remove the applied deviations and augments */
1398 lys_sub_module_remove_devs_augs((struct lys_module *)mods->set.g[u]);
Radek Krejci85a54be2016-10-20 12:39:56 +02001399 /* remove the module */
Michal Vasko10681e82018-01-16 14:54:16 +01001400 lys_free((struct lys_module *)mods->set.g[u], private_destructor, 1, 0);
Radek Krejci85a54be2016-10-20 12:39:56 +02001401 }
1402 ly_set_free(mods);
1403
Radek Krejci8c107fe2016-10-17 16:00:18 +02001404 return EXIT_SUCCESS;
1405}
1406
Radek Krejci85a54be2016-10-20 12:39:56 +02001407API void
1408ly_ctx_clean(struct ly_ctx *ctx, void (*private_destructor)(const struct lys_node *node, void *priv))
1409{
Radek Krejci85a54be2016-10-20 12:39:56 +02001410 if (!ctx) {
1411 return;
1412 }
1413
1414 /* models list */
Radek Krejcidfb00d62017-09-06 09:39:35 +02001415 for (; ctx->models.used > ctx->internal_module_count; ctx->models.used--) {
Radek Krejcifc8411a2017-02-03 10:26:05 +01001416 /* remove the applied deviations and augments */
Radek Krejcic436a232017-02-08 14:43:11 +01001417 lys_sub_module_remove_devs_augs(ctx->models.list[ctx->models.used - 1]);
Radek Krejcifc8411a2017-02-03 10:26:05 +01001418 /* remove the module */
Michal Vasko10681e82018-01-16 14:54:16 +01001419 lys_free(ctx->models.list[ctx->models.used - 1], private_destructor, 1, 0);
Radek Krejcifc8411a2017-02-03 10:26:05 +01001420 /* clean it for safer future use */
Radek Krejcic436a232017-02-08 14:43:11 +01001421 ctx->models.list[ctx->models.used - 1] = NULL;
Radek Krejci85a54be2016-10-20 12:39:56 +02001422 }
Radek Krejci85a54be2016-10-20 12:39:56 +02001423 ctx->models.module_set_id++;
1424
Radek Krejci83a4bac2017-02-07 15:53:04 +01001425 /* maintain backlinks (actually done only with ietf-yang-library since its leafs can be target of leafref) */
Michal Vasko4be5fa22017-02-07 10:12:32 +01001426 ctx_modules_undo_backlinks(ctx, NULL);
Radek Krejci85a54be2016-10-20 12:39:56 +02001427}
1428
Michal Vaskod7957c02016-04-01 10:27:26 +02001429API const struct lys_module *
1430ly_ctx_get_module_iter(const struct ly_ctx *ctx, uint32_t *idx)
1431{
1432 if (!ctx || !idx) {
Michal Vasko53b7da02018-02-13 15:28:42 +01001433 LOGARG;
Michal Vaskod7957c02016-04-01 10:27:26 +02001434 return NULL;
1435 }
1436
Radek Krejci0ec51da2016-12-14 16:42:03 +01001437 for ( ; *idx < (unsigned)ctx->models.used; (*idx)++) {
1438 if (!ctx->models.list[(*idx)]->disabled) {
1439 return ctx->models.list[(*idx)++];
1440 }
1441 }
1442
1443 return NULL;
1444}
1445
1446API const struct lys_module *
1447ly_ctx_get_disabled_module_iter(const struct ly_ctx *ctx, uint32_t *idx)
1448{
1449 if (!ctx || !idx) {
Michal Vasko53b7da02018-02-13 15:28:42 +01001450 LOGARG;
Michal Vaskod7957c02016-04-01 10:27:26 +02001451 return NULL;
1452 }
1453
Radek Krejci0ec51da2016-12-14 16:42:03 +01001454 for ( ; *idx < (unsigned)ctx->models.used; (*idx)++) {
1455 if (ctx->models.list[(*idx)]->disabled) {
1456 return ctx->models.list[(*idx)++];
1457 }
1458 }
1459
1460 return NULL;
Michal Vaskod7957c02016-04-01 10:27:26 +02001461}
1462
Michal Vasko209a6222015-10-16 09:51:07 +02001463static int
Michal Vaskoeb3bd0e2018-01-26 11:52:11 +01001464ylib_feature(struct lyd_node *parent, struct lys_module *cur_mod, int bis)
Michal Vasko209a6222015-10-16 09:51:07 +02001465{
1466 int i, j;
Michal Vaskoeb3bd0e2018-01-26 11:52:11 +01001467 struct lyd_node *list;
Michal Vasko209a6222015-10-16 09:51:07 +02001468
1469 /* module features */
1470 for (i = 0; i < cur_mod->features_size; ++i) {
1471 if (!(cur_mod->features[i].flags & LYS_FENABLED)) {
1472 continue;
1473 }
1474
Michal Vaskoeb3bd0e2018-01-26 11:52:11 +01001475 if (bis) {
1476 if (!(list = lyd_new(parent, NULL, "feature")) || !lyd_new_leaf(list, NULL, "name", cur_mod->features[i].name)) {
1477 return EXIT_FAILURE;
1478 }
1479 } else if (!lyd_new_leaf(parent, NULL, "feature", cur_mod->features[i].name)) {
Michal Vasko209a6222015-10-16 09:51:07 +02001480 return EXIT_FAILURE;
1481 }
1482 }
1483
1484 /* submodule features */
Radek Krejcic071c542016-01-27 14:57:51 +01001485 for (i = 0; i < cur_mod->inc_size && cur_mod->inc[i].submodule; ++i) {
Michal Vasko209a6222015-10-16 09:51:07 +02001486 for (j = 0; j < cur_mod->inc[i].submodule->features_size; ++j) {
1487 if (!(cur_mod->inc[i].submodule->features[j].flags & LYS_FENABLED)) {
1488 continue;
1489 }
1490
Michal Vaskoeb3bd0e2018-01-26 11:52:11 +01001491 if (bis) {
1492 if (!(list = lyd_new(parent, NULL, "feature"))
1493 || !lyd_new_leaf(list, NULL, "name", cur_mod->inc[i].submodule->features[j].name)) {
1494 return EXIT_FAILURE;
1495 }
1496 } else if (!lyd_new_leaf(parent, NULL, "feature", cur_mod->inc[i].submodule->features[j].name)) {
Michal Vasko209a6222015-10-16 09:51:07 +02001497 return EXIT_FAILURE;
1498 }
1499 }
1500 }
1501
1502 return EXIT_SUCCESS;
1503}
1504
1505static int
Michal Vaskoeb3bd0e2018-01-26 11:52:11 +01001506ylib_deviation(struct lyd_node *parent, struct lys_module *cur_mod, int bis)
Michal Vasko97d8c6d2016-02-12 11:05:48 +01001507{
Michal Vasko89563fc2016-07-28 16:19:35 +02001508 uint32_t i = 0, j;
1509 const struct lys_module *mod;
Michal Vasko209a6222015-10-16 09:51:07 +02001510 struct lyd_node *cont;
Michal Vasko89563fc2016-07-28 16:19:35 +02001511 const char *ptr;
Michal Vasko209a6222015-10-16 09:51:07 +02001512
Michal Vasko89563fc2016-07-28 16:19:35 +02001513 if (cur_mod->deviated) {
1514 while ((mod = ly_ctx_get_module_iter(cur_mod->ctx, &i))) {
1515 if (mod == cur_mod) {
1516 continue;
Michal Vasko209a6222015-10-16 09:51:07 +02001517 }
Michal Vasko209a6222015-10-16 09:51:07 +02001518
Michal Vasko89563fc2016-07-28 16:19:35 +02001519 for (j = 0; j < mod->deviation_size; ++j) {
1520 ptr = strstr(mod->deviation[j].target_name, cur_mod->name);
1521 if (ptr && ptr[strlen(cur_mod->name)] == ':') {
1522 cont = lyd_new(parent, NULL, "deviation");
1523 if (!cont) {
1524 return EXIT_FAILURE;
1525 }
1526
Michal Vaskoeb3bd0e2018-01-26 11:52:11 +01001527 if (bis) {
1528 if (!lyd_new_leaf(cont, NULL, "module", mod->name)) {
1529 return EXIT_FAILURE;
1530 }
1531 } else {
1532 if (!lyd_new_leaf(cont, NULL, "name", mod->name)) {
1533 return EXIT_FAILURE;
1534 }
1535 if (!lyd_new_leaf(cont, NULL, "revision", (mod->rev_size ? mod->rev[0].date : ""))) {
1536 return EXIT_FAILURE;
1537 }
Michal Vasko89563fc2016-07-28 16:19:35 +02001538 }
Michal Vasko0c2215b2016-08-25 14:18:43 +02001539
1540 break;
Michal Vasko89563fc2016-07-28 16:19:35 +02001541 }
Michal Vasko209a6222015-10-16 09:51:07 +02001542 }
1543 }
1544 }
1545
1546 return EXIT_SUCCESS;
1547}
1548
1549static int
Michal Vaskoeb3bd0e2018-01-26 11:52:11 +01001550ylib_submodules(struct lyd_node *parent, struct lys_module *cur_mod, int bis)
Michal Vasko209a6222015-10-16 09:51:07 +02001551{
1552 int i;
Radek Krejcia77904e2016-02-25 16:23:45 +01001553 char *str;
Radek Krejcid9723912016-09-16 17:06:06 +02001554 struct lyd_node *item;
Michal Vasko209a6222015-10-16 09:51:07 +02001555
Radek Krejcic071c542016-01-27 14:57:51 +01001556 for (i = 0; i < cur_mod->inc_size && cur_mod->inc[i].submodule; ++i) {
Radek Krejcid9723912016-09-16 17:06:06 +02001557 item = lyd_new(parent, NULL, "submodule");
Radek Krejci6e05cea2015-12-10 16:34:37 +01001558 if (!item) {
Michal Vasko209a6222015-10-16 09:51:07 +02001559 return EXIT_FAILURE;
1560 }
1561
Radek Krejci6e05cea2015-12-10 16:34:37 +01001562 if (!lyd_new_leaf(item, NULL, "name", cur_mod->inc[i].submodule->name)) {
Michal Vasko209a6222015-10-16 09:51:07 +02001563 return EXIT_FAILURE;
1564 }
Michal Vaskoeb3bd0e2018-01-26 11:52:11 +01001565 if ((!bis || cur_mod->inc[i].submodule->rev_size)
1566 && !lyd_new_leaf(item, NULL, "revision",
1567 (cur_mod->inc[i].submodule->rev_size ? cur_mod->inc[i].submodule->rev[0].date : ""))) {
Michal Vasko209a6222015-10-16 09:51:07 +02001568 return EXIT_FAILURE;
1569 }
Radek Krejcia77904e2016-02-25 16:23:45 +01001570 if (cur_mod->inc[i].submodule->filepath) {
Radek Krejci95aa2012016-03-03 11:21:09 +01001571 if (asprintf(&str, "file://%s", cur_mod->inc[i].submodule->filepath) == -1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01001572 LOGMEM(cur_mod->ctx);
Radek Krejcia77904e2016-02-25 16:23:45 +01001573 return EXIT_FAILURE;
Michal Vaskoeb3bd0e2018-01-26 11:52:11 +01001574 } else if (!lyd_new_leaf(item, NULL, bis ? "location" : "schema", str)) {
Radek Krejci19f9ede2016-02-25 16:29:21 +01001575 free(str);
Radek Krejcia77904e2016-02-25 16:23:45 +01001576 return EXIT_FAILURE;
1577 }
Radek Krejci19f9ede2016-02-25 16:29:21 +01001578 free(str);
Michal Vasko209a6222015-10-16 09:51:07 +02001579 }
1580 }
1581
1582 return EXIT_SUCCESS;
1583}
1584
1585API struct lyd_node *
1586ly_ctx_info(struct ly_ctx *ctx)
1587{
Radek Krejcidfb00d62017-09-06 09:39:35 +02001588 int i, bis = 0;
Michal Vasko209a6222015-10-16 09:51:07 +02001589 char id[8];
Radek Krejcia77904e2016-02-25 16:23:45 +01001590 char *str;
Michal Vasko1e62a092015-12-01 12:27:20 +01001591 const struct lys_module *mod;
Michal Vaskoeb3bd0e2018-01-26 11:52:11 +01001592 struct lyd_node *root, *root_bis = NULL, *cont = NULL, *set_bis = NULL;
Michal Vasko209a6222015-10-16 09:51:07 +02001593
Michal Vasko7eccc6c2016-03-24 14:56:33 +01001594 if (!ctx) {
Michal Vasko53b7da02018-02-13 15:28:42 +01001595 LOGARG;
Michal Vasko7eccc6c2016-03-24 14:56:33 +01001596 return NULL;
1597 }
1598
Radek Krejcidfb00d62017-09-06 09:39:35 +02001599 mod = ly_ctx_get_module(ctx, "ietf-yang-library", NULL, 1);
Radek Krejcibd9e8d22016-02-03 14:11:48 +01001600 if (!mod || !mod->data) {
Michal Vasko53b7da02018-02-13 15:28:42 +01001601 LOGERR(ctx, LY_EINVAL, "ietf-yang-library is not implemented.");
Radek Krejcidfb00d62017-09-06 09:39:35 +02001602 return NULL;
1603 }
Michal Vaskoeb3bd0e2018-01-26 11:52:11 +01001604 if (mod->rev && !strcmp(mod->rev[0].date, "2016-04-09")) {
Radek Krejcidfb00d62017-09-06 09:39:35 +02001605 bis = 0;
1606 } else if (mod->rev && !strcmp(mod->rev[0].date, IETF_YANG_LIB_REV)) {
1607 bis = 1;
1608 } else {
Michal Vasko53b7da02018-02-13 15:28:42 +01001609 LOGERR(ctx, LY_EINVAL, "Incompatible ietf-yang-library version in context.");
Michal Vasko209a6222015-10-16 09:51:07 +02001610 return NULL;
1611 }
1612
Radek Krejcibd9e8d22016-02-03 14:11:48 +01001613 root = lyd_new(NULL, mod, "modules-state");
Michal Vasko209a6222015-10-16 09:51:07 +02001614 if (!root) {
1615 return NULL;
1616 }
1617
Radek Krejcidfb00d62017-09-06 09:39:35 +02001618 if (bis) {
Michal Vaskoeb3bd0e2018-01-26 11:52:11 +01001619 if (!(root_bis = lyd_new(NULL, mod, "yang-library")) || !(set_bis = lyd_new(root_bis, NULL, "module-set"))) {
1620 goto error;
1621 }
1622
1623 if (!lyd_new_leaf(set_bis, NULL, "name", "complete")) {
1624 goto error;
1625 }
1626
1627 sprintf(id, "%u", ctx->models.module_set_id);
1628 if (!lyd_new_leaf(set_bis, NULL, "checksum", id)) {
Radek Krejcidfb00d62017-09-06 09:39:35 +02001629 goto error;
1630 }
1631 }
1632
Michal Vasko209a6222015-10-16 09:51:07 +02001633 for (i = 0; i < ctx->models.used; ++i) {
Radek Krejci0ec51da2016-12-14 16:42:03 +01001634 if (ctx->models.list[i]->disabled) {
1635 /* skip the disabled modules */
1636 continue;
1637 }
1638
Michal Vaskoeb3bd0e2018-01-26 11:52:11 +01001639 /*
1640 * deprecated legacy
1641 */
1642 cont = lyd_new(root, NULL, "module");
Michal Vasko209a6222015-10-16 09:51:07 +02001643 if (!cont) {
Radek Krejcidfb00d62017-09-06 09:39:35 +02001644 goto error;
1645 }
Radek Krejcidfb00d62017-09-06 09:39:35 +02001646 /* name */
Michal Vaskoeb3bd0e2018-01-26 11:52:11 +01001647 if (!lyd_new_leaf(cont, NULL, "name", ctx->models.list[i]->name)) {
Radek Krejcidfb00d62017-09-06 09:39:35 +02001648 goto error;
1649 }
1650 /* revision */
Michal Vaskoeb3bd0e2018-01-26 11:52:11 +01001651 if (!lyd_new_leaf(cont, NULL, "revision", (ctx->models.list[i]->rev_size ? ctx->models.list[i]->rev[0].date : ""))) {
Radek Krejcidfb00d62017-09-06 09:39:35 +02001652 goto error;
1653 }
1654 /* schema */
Radek Krejcia77904e2016-02-25 16:23:45 +01001655 if (ctx->models.list[i]->filepath) {
Radek Krejci15412ca2016-03-03 11:16:52 +01001656 if (asprintf(&str, "file://%s", ctx->models.list[i]->filepath) == -1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01001657 LOGMEM(ctx);
Radek Krejcidfb00d62017-09-06 09:39:35 +02001658 goto error;
1659 }
Michal Vaskoeb3bd0e2018-01-26 11:52:11 +01001660 if (!lyd_new_leaf(cont, NULL, "schema", str)) {
Radek Krejcidfb00d62017-09-06 09:39:35 +02001661 free(str);
1662 goto error;
Radek Krejcia77904e2016-02-25 16:23:45 +01001663 }
Radek Krejci19f9ede2016-02-25 16:29:21 +01001664 free(str);
Michal Vasko209a6222015-10-16 09:51:07 +02001665 }
Radek Krejcidfb00d62017-09-06 09:39:35 +02001666 /* namespace */
Michal Vaskoeb3bd0e2018-01-26 11:52:11 +01001667 if (!lyd_new_leaf(cont, NULL, "namespace", ctx->models.list[i]->ns)) {
Radek Krejcidfb00d62017-09-06 09:39:35 +02001668 goto error;
1669 }
1670 /* feature leaf-list */
Michal Vaskoeb3bd0e2018-01-26 11:52:11 +01001671 if (ylib_feature(cont, ctx->models.list[i], 0)) {
Radek Krejcidfb00d62017-09-06 09:39:35 +02001672 goto error;
1673 }
1674 /* deviation list */
Michal Vaskoeb3bd0e2018-01-26 11:52:11 +01001675 if (ylib_deviation(cont, ctx->models.list[i], 0)) {
Radek Krejcidfb00d62017-09-06 09:39:35 +02001676 goto error;
Michal Vasko209a6222015-10-16 09:51:07 +02001677 }
Radek Krejcidfb00d62017-09-06 09:39:35 +02001678 /* conformance-type */
Michal Vaskoeb3bd0e2018-01-26 11:52:11 +01001679 if (!lyd_new_leaf(cont, NULL, "conformance-type", ctx->models.list[i]->implemented ? "implement" : "import")) {
Radek Krejcidfb00d62017-09-06 09:39:35 +02001680 goto error;
1681 }
1682 /* submodule list */
Michal Vaskoeb3bd0e2018-01-26 11:52:11 +01001683 if (ylib_submodules(cont, ctx->models.list[i], 0)) {
Radek Krejcidfb00d62017-09-06 09:39:35 +02001684 goto error;
1685 }
Radek Krejcidfb00d62017-09-06 09:39:35 +02001686
Michal Vaskoeb3bd0e2018-01-26 11:52:11 +01001687 /*
1688 * current revision
1689 */
1690 if (bis) {
1691 if (ctx->models.list[i]->implemented) {
1692 if (!(cont = lyd_new(set_bis, NULL, "module"))) {
1693 goto error;
1694 }
1695 } else {
1696 if (!(cont = lyd_new(set_bis, NULL, "import-only-module"))) {
1697 goto error;
1698 }
1699 }
1700 /* name */
1701 if (!lyd_new_leaf(cont, NULL, "name", ctx->models.list[i]->name)) {
Radek Krejcidfb00d62017-09-06 09:39:35 +02001702 goto error;
1703 }
Michal Vaskoeb3bd0e2018-01-26 11:52:11 +01001704 /* revision */
1705 if ((!ctx->models.list[i]->implemented || ctx->models.list[i]->rev_size)
1706 && !lyd_new_leaf(cont, NULL, "revision", ctx->models.list[i]->rev[0].date)) {
1707 goto error;
1708 }
1709 /* namespace */
1710 if (!lyd_new_leaf(cont, NULL, "namespace", ctx->models.list[i]->ns)) {
1711 goto error;
1712 }
1713 /* location */
1714 if (ctx->models.list[i]->filepath) {
1715 if (asprintf(&str, "file://%s", ctx->models.list[i]->filepath) == -1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01001716 LOGMEM(ctx);
Michal Vaskoeb3bd0e2018-01-26 11:52:11 +01001717 goto error;
1718 }
1719 if (!lyd_new_leaf(cont, NULL, "location", str)) {
1720 free(str);
1721 goto error;
1722 }
1723 free(str);
1724 }
1725 /* submodule list */
1726 if (ylib_submodules(cont, ctx->models.list[i], 1)) {
1727 goto error;
1728 }
1729 if (ctx->models.list[i]->implemented) {
1730 /* feature list */
1731 if (ylib_feature(cont, ctx->models.list[i], 1)) {
1732 goto error;
1733 }
1734 /* deviation */
1735 if (ylib_deviation(cont, ctx->models.list[i], 1)) {
1736 goto error;
1737 }
1738 }
Michal Vasko209a6222015-10-16 09:51:07 +02001739 }
1740 }
1741
1742 sprintf(id, "%u", ctx->models.module_set_id);
Michal Vaskoeb3bd0e2018-01-26 11:52:11 +01001743 if (!lyd_new_leaf(root, NULL, "module-set-id", id)) {
Radek Krejcidfb00d62017-09-06 09:39:35 +02001744 goto error;
1745 }
Michal Vaskoeb3bd0e2018-01-26 11:52:11 +01001746 if (bis && !lyd_new_leaf(root_bis, NULL, "checksum", id)) {
Radek Krejcidfb00d62017-09-06 09:39:35 +02001747 goto error;
1748 }
1749
1750 if (root_bis) {
1751 if (lyd_insert_sibling(&root_bis, root)) {
1752 goto error;
1753 }
1754 root = root_bis;
1755 root_bis = 0;
Michal Vasko209a6222015-10-16 09:51:07 +02001756 }
1757
Michal Vaskocdb90172016-09-13 09:34:36 +02001758 if (lyd_validate(&root, LYD_OPT_NOSIBLINGS, NULL)) {
Radek Krejcidfb00d62017-09-06 09:39:35 +02001759 goto error;
Michal Vasko209a6222015-10-16 09:51:07 +02001760 }
1761
1762 return root;
Radek Krejcidfb00d62017-09-06 09:39:35 +02001763
1764error:
1765 lyd_free_withsiblings(root);
1766 lyd_free_withsiblings(root_bis);
1767 return NULL;
Michal Vasko209a6222015-10-16 09:51:07 +02001768}
Michal Vaskob3744402017-08-03 14:23:58 +02001769
1770API const struct lys_node *
1771ly_ctx_get_node(struct ly_ctx *ctx, const struct lys_node *start, const char *nodeid, int output)
1772{
1773 const struct lys_node *node;
1774
Michal Vaskob3a6e482017-09-14 13:50:28 +02001775 if ((!ctx && !start) || !nodeid || ((nodeid[0] != '/') && !start)) {
Michal Vasko53b7da02018-02-13 15:28:42 +01001776 LOGARG;
Michal Vaskob3744402017-08-03 14:23:58 +02001777 return NULL;
1778 }
1779
Michal Vaskob3a6e482017-09-14 13:50:28 +02001780 if (!ctx) {
1781 ctx = start->module->ctx;
1782 }
1783
Michal Vaskob3744402017-08-03 14:23:58 +02001784 /* sets error and everything */
1785 node = resolve_json_nodeid(nodeid, ctx, start, output);
1786
1787 return node;
1788}
Radek Krejci749ebf52018-01-22 11:40:36 +01001789
Radek Krejcic683acd2018-01-22 14:51:52 +01001790API struct ly_set *
1791ly_ctx_find_path(struct ly_ctx *ctx, const char *path)
Radek Krejci749ebf52018-01-22 11:40:36 +01001792{
1793 struct ly_set *resultset = NULL;
Radek Krejci749ebf52018-01-22 11:40:36 +01001794
Radek Krejcic683acd2018-01-22 14:51:52 +01001795 if (!ctx || !path) {
Michal Vasko53b7da02018-02-13 15:28:42 +01001796 LOGARG;
Radek Krejci749ebf52018-01-22 11:40:36 +01001797 return NULL;
1798 }
1799
1800 /* start in internal module without data to make sure that all the nodes are prefixed */
Radek Krejcic683acd2018-01-22 14:51:52 +01001801 resolve_schema_nodeid(path, NULL, ctx->models.list[0], &resultset, 1, 1);
1802 return resultset;
Radek Krejci749ebf52018-01-22 11:40:36 +01001803}