blob: b74e91d062bcb0a13cfe21170564dcb71f95fcbd [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 Krejcid9723912016-09-16 17:06:06 +020043#define IETF_YANG_LIB_PATH "../models/ietf-yang-library@2016-06-21.h"
44#define IETF_YANG_LIB_REV "2016-06-21"
Michal Vasko8d054e42015-08-03 12:42:06 +020045
Radek Krejci532e5e92017-02-22 12:59:24 +010046#include IETF_YANG_METADATA_PATH
47#include YANG_PATH
Michal Vasko8d054e42015-08-03 12:42:06 +020048#include IETF_INET_TYPES_PATH
Michal Vasko21181c42015-08-03 13:46:45 +020049#include IETF_YANG_TYPES_PATH
Michal Vasko8d054e42015-08-03 12:42:06 +020050#include IETF_YANG_LIB_PATH
51
Radek Krejci03203412016-06-23 15:20:53 +020052static struct internal_modules_s {
53 const char *name;
54 const char *revision;
55 const char *data;
56 uint8_t implemented;
57 LYS_INFORMAT format;
Michal Vasko2d051a12017-04-21 09:28:57 +020058} internal_modules[LY_INTERNAL_MODULE_COUNT] = {
Radek Krejci532e5e92017-02-22 12:59:24 +010059 {"ietf-yang-metadata", "2016-08-05", (const char*)ietf_yang_metadata_2016_08_05_yin, 0, LYS_IN_YIN},
60 {"yang", "2017-02-20", (const char*)yang_2017_02_20_yin, 1, LYS_IN_YIN},
Radek Krejci03203412016-06-23 15:20:53 +020061 {"ietf-inet-types", "2013-07-15", (const char*)ietf_inet_types_2013_07_15_yin, 0, LYS_IN_YIN},
62 {"ietf-yang-types", "2013-07-15", (const char*)ietf_yang_types_2013_07_15_yin, 0, LYS_IN_YIN},
Radek Krejci06f8bb92017-08-02 15:36:25 +020063 /* ietf-yang-library is expected at (LY_INTERNAL_MODULE_COUNT - 1) position! */
Radek Krejcid9723912016-09-16 17:06:06 +020064 {"ietf-yang-library", "2016-06-21", (const char*)ietf_yang_library_2016_06_21_yin, 1, LYS_IN_YIN}
Radek Krejci03203412016-06-23 15:20:53 +020065};
66
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020067API struct ly_ctx *
68ly_ctx_new(const char *search_dir)
Radek Krejcida04f4a2015-05-21 12:54:09 +020069{
Radek Krejcia8d111f2017-05-31 13:57:37 +020070 struct ly_ctx *ctx = NULL;
Michal Vasko7d7de952016-05-02 17:13:14 +020071 struct lys_module *module;
Radek Krejcia8d111f2017-05-31 13:57:37 +020072 char *cwd = NULL;
Radek Krejci03203412016-06-23 15:20:53 +020073 int i;
Radek Krejcida04f4a2015-05-21 12:54:09 +020074
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020075 ctx = calloc(1, sizeof *ctx);
Radek Krejcia8d111f2017-05-31 13:57:37 +020076 LY_CHECK_ERR_RETURN(!ctx, LOGMEM, NULL);
Radek Krejcida04f4a2015-05-21 12:54:09 +020077
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020078 /* dictionary */
79 lydict_init(&ctx->dict);
Radek Krejcida04f4a2015-05-21 12:54:09 +020080
Radek Krejci858ad952017-01-04 11:16:32 +010081 /* plugins */
Radek Krejci858ad952017-01-04 11:16:32 +010082 lyext_load_plugins();
83
Radek Krejcicf748252017-09-04 11:11:14 +020084 /* initialize thread-specific key */
85 while ((i = pthread_key_create(&ctx->errlist_key, ly_err_free)) == EAGAIN);
86
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020087 /* models list */
88 ctx->models.list = calloc(16, sizeof *ctx->models.list);
Radek Krejcia8d111f2017-05-31 13:57:37 +020089 LY_CHECK_ERR_RETURN(!ctx->models.list, LOGMEM; free(ctx), NULL);
Radek Krejci37d02632017-02-21 14:14:11 +010090 ext_plugins_ref++;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020091 ctx->models.used = 0;
92 ctx->models.size = 16;
93 if (search_dir) {
94 cwd = get_current_dir_name();
95 if (chdir(search_dir)) {
96 LOGERR(LY_ESYS, "Unable to use search directory \"%s\" (%s)",
97 search_dir, strerror(errno));
Radek Krejcia8d111f2017-05-31 13:57:37 +020098 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020099 }
Radek Krejcida9f8392017-03-25 19:40:56 -0500100 ctx->models.search_paths = malloc(2 * sizeof *ctx->models.search_paths);
Radek Krejcia8d111f2017-05-31 13:57:37 +0200101 LY_CHECK_ERR_GOTO(!ctx->models.search_paths, LOGMEM, error);
Radek Krejcida9f8392017-03-25 19:40:56 -0500102 ctx->models.search_paths[0] = get_current_dir_name();
103 ctx->models.search_paths[1] = NULL;
Radek Krejci15412ca2016-03-03 11:16:52 +0100104 if (chdir(cwd)) {
105 LOGWRN("Unable to return back to working directory \"%s\" (%s)",
106 cwd, strerror(errno));
107 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200108 }
Michal Vasko14719b22015-08-03 12:47:55 +0200109 ctx->models.module_set_id = 1;
110
Radek Krejci03203412016-06-23 15:20:53 +0200111 /* load internal modules */
Michal Vasko2d051a12017-04-21 09:28:57 +0200112 for (i = 0; i < LY_INTERNAL_MODULE_COUNT; i++) {
Radek Krejci03203412016-06-23 15:20:53 +0200113 module = (struct lys_module *)lys_parse_mem(ctx, internal_modules[i].data, internal_modules[i].format);
114 if (!module) {
Radek Krejcia8d111f2017-05-31 13:57:37 +0200115 goto error;
Radek Krejci03203412016-06-23 15:20:53 +0200116 }
117 module->implemented = internal_modules[i].implemented;
Michal Vasko8d054e42015-08-03 12:42:06 +0200118 }
Radek Krejcida04f4a2015-05-21 12:54:09 +0200119
Radek Krejcia8d111f2017-05-31 13:57:37 +0200120 /* cleanup */
121 free(cwd);
122
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200123 return ctx;
Radek Krejcia8d111f2017-05-31 13:57:37 +0200124
125error:
126 free(cwd);
127 ly_ctx_destroy(ctx, NULL);
128 return NULL;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200129}
130
Radek Krejci69333c92017-03-17 16:14:43 +0100131static struct ly_ctx *
132ly_ctx_new_yl_common(const char *search_dir, const char *input, LYD_FORMAT format,
133 struct lyd_node* (*parser_func)(struct ly_ctx*, const char*, LYD_FORMAT, int,...))
134{
135 unsigned int u;
136 struct lyd_node *module, *node;
137 const char *name, *revision;
Radek Krejci5cb217d2017-03-25 16:07:52 -0500138 struct ly_set features = {0, 0, {NULL}};
Radek Krejci69333c92017-03-17 16:14:43 +0100139 const struct lys_module *mod;
140 struct lyd_node *yltree = NULL;
141 struct ly_ctx *ctx = NULL;
142
143 /* create empty (with internal modules including ietf-yang-library) context */
144 ctx = ly_ctx_new(search_dir);
145 if (!ctx) {
146 goto error;
147 }
148
149 /* parse yang library data tree */
150 yltree = parser_func(ctx, input, format, LYD_OPT_DATA, NULL);
151 if (!yltree) {
152 goto error;
153 }
154
155 /* process the data tree */
156 LY_TREE_FOR(yltree->child, module) {
157 if (module->schema->nodetype == LYS_LEAF) {
158 /* module-set-id - ignore it */
159 continue;
160 }
161
162 /* initiate */
163 name = NULL;
164 revision = NULL;
165 ly_set_clean(&features);
166
167 LY_TREE_FOR(module->child, node) {
168 if (!strcmp(node->schema->name, "name")) {
169 name = ((struct lyd_node_leaf_list*)node)->value_str;
170 } else if (!strcmp(node->schema->name, "revision")) {
171 revision = ((struct lyd_node_leaf_list*)node)->value_str;
172 } else if (!strcmp(node->schema->name, "feature")) {
173 ly_set_add(&features, node, LY_SET_OPT_USEASLIST);
174 } else if (!strcmp(node->schema->name, "conformance-type") &&
175 ((struct lyd_node_leaf_list*)node)->value.enm->value) {
176 /* imported module - skip it, it will be loaded as a side effect
177 * of loading another module */
178 goto next_module;
179 }
180 }
181
182 /* use the gathered data to load the module */
183 mod = ly_ctx_load_module(ctx, name, revision);
184 if (!mod) {
185 LOGERR(LY_EINVAL, "Unable to load module specified by yang library data.");
186 goto error;
187 }
188
189 /* set features */
190 for (u = 0; u < features.number; u++) {
191 lys_features_enable(mod, ((struct lyd_node_leaf_list*)features.set.d[u])->value_str);
192 }
193
194next_module:;
195 }
196
197 if (0) {
198 /* skip context destroy in case of success */
199error:
200 ly_ctx_destroy(ctx, NULL);
201 ctx = NULL;
202 }
203
204 /* cleanup */
205 if (yltree) {
206 /* yang library data tree */
207 lyd_free_withsiblings(yltree);
208 }
209
210 return ctx;
211}
212
213API struct ly_ctx *
214ly_ctx_new_ylpath(const char *search_dir, const char *path, LYD_FORMAT format)
215{
216 return ly_ctx_new_yl_common(search_dir, path, format, lyd_parse_path);
217}
218
219API struct ly_ctx *
220ly_ctx_new_ylmem(const char *search_dir, const char *data, LYD_FORMAT format)
221{
222 return ly_ctx_new_yl_common(search_dir, data, format, lyd_parse_mem);
223}
224
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200225API void
Radek Krejci819dd4b2017-03-07 15:35:48 +0100226ly_ctx_set_allimplemented(struct ly_ctx *ctx)
227{
228 if (!ctx) {
229 return;
230 }
231
232 ctx->models.flags |= LY_CTX_ALLIMPLEMENTED;
233}
234
235API void
236ly_ctx_unset_allimplemented(struct ly_ctx *ctx)
237{
238 if (!ctx) {
239 return;
240 }
241
242 ctx->models.flags &= ~LY_CTX_ALLIMPLEMENTED;
243}
244
245API void
Michal Vasko60ba9a62015-07-03 14:42:31 +0200246ly_ctx_set_searchdir(struct ly_ctx *ctx, const char *search_dir)
247{
Radek Krejcia62a9d12017-08-09 12:37:51 +0200248 char *cwd = NULL, *new = NULL;
Radek Krejcida9f8392017-03-25 19:40:56 -0500249 int index = 0;
250 void *r;
Michal Vasko60ba9a62015-07-03 14:42:31 +0200251
252 if (!ctx) {
253 return;
254 }
255
256 if (search_dir) {
257 cwd = get_current_dir_name();
258 if (chdir(search_dir)) {
259 LOGERR(LY_ESYS, "Unable to use search directory \"%s\" (%s)",
260 search_dir, strerror(errno));
Radek Krejcia8d111f2017-05-31 13:57:37 +0200261 goto cleanup;
Michal Vasko60ba9a62015-07-03 14:42:31 +0200262 }
Radek Krejcida9f8392017-03-25 19:40:56 -0500263
Radek Krejci426ea2b2017-06-13 12:41:51 +0200264 new = get_current_dir_name();
Radek Krejcida9f8392017-03-25 19:40:56 -0500265 if (!ctx->models.search_paths) {
266 ctx->models.search_paths = malloc(2 * sizeof *ctx->models.search_paths);
Radek Krejcia8d111f2017-05-31 13:57:37 +0200267 LY_CHECK_ERR_GOTO(!ctx->models.search_paths, LOGMEM, cleanup);
Radek Krejcida9f8392017-03-25 19:40:56 -0500268 index = 0;
269 } else {
Radek Krejci426ea2b2017-06-13 12:41:51 +0200270 for (index = 0; ctx->models.search_paths[index]; index++) {
271 /* check for duplicities */
272 if (!strcmp(new, ctx->models.search_paths[index])) {
273 /* path is already present */
Radek Krejci426ea2b2017-06-13 12:41:51 +0200274 goto success;
275 }
276 }
Radek Krejcida9f8392017-03-25 19:40:56 -0500277 r = realloc(ctx->models.search_paths, (index + 2) * sizeof *ctx->models.search_paths);
Radek Krejcia8d111f2017-05-31 13:57:37 +0200278 LY_CHECK_ERR_GOTO(!r, LOGMEM, cleanup);
Radek Krejcida9f8392017-03-25 19:40:56 -0500279 ctx->models.search_paths = r;
280 }
Radek Krejci426ea2b2017-06-13 12:41:51 +0200281 ctx->models.search_paths[index] = new;
Radek Krejcia62a9d12017-08-09 12:37:51 +0200282 new = NULL;
Radek Krejcida9f8392017-03-25 19:40:56 -0500283 ctx->models.search_paths[index + 1] = NULL;
Michal Vasko3eff9322015-11-10 11:02:30 +0100284
Radek Krejci426ea2b2017-06-13 12:41:51 +0200285success:
Radek Krejci15412ca2016-03-03 11:16:52 +0100286 if (chdir(cwd)) {
287 LOGWRN("Unable to return back to working directory \"%s\" (%s)",
288 cwd, strerror(errno));
289 }
Michal Vasko60ba9a62015-07-03 14:42:31 +0200290 }
Radek Krejcia8d111f2017-05-31 13:57:37 +0200291
292cleanup:
293 free(cwd);
Radek Krejcia62a9d12017-08-09 12:37:51 +0200294 free(new);
Michal Vasko60ba9a62015-07-03 14:42:31 +0200295}
296
Radek Krejci426ea2b2017-06-13 12:41:51 +0200297API const char * const *
298ly_ctx_get_searchdirs(const struct ly_ctx *ctx)
Radek Krejci5a797572015-10-21 15:45:45 +0200299{
Radek Krejciee554172016-12-14 10:29:06 +0100300 if (!ctx) {
301 ly_errno = LY_EINVAL;
302 return NULL;
303 }
Radek Krejci426ea2b2017-06-13 12:41:51 +0200304 return (const char * const *)ctx->models.search_paths;
Radek Krejcida9f8392017-03-25 19:40:56 -0500305}
306
307API void
Radek Krejcidb4e9ff2017-06-13 16:26:14 +0200308ly_ctx_unset_searchdirs(struct ly_ctx *ctx, int index)
Radek Krejcida9f8392017-03-25 19:40:56 -0500309{
310 int i;
311
312 if (!ctx->models.search_paths) {
313 return;
314 }
315
316 for (i = 0; ctx->models.search_paths[i]; i++) {
Radek Krejcidb4e9ff2017-06-13 16:26:14 +0200317 if (index < 0 || index == i) {
318 free(ctx->models.search_paths[i]);
319 ctx->models.search_paths[i] = NULL;
320 } else if (i > index) {
321 ctx->models.search_paths[i - 1] = ctx->models.search_paths[i];
322 ctx->models.search_paths[i] = NULL;
323 }
Radek Krejcida9f8392017-03-25 19:40:56 -0500324 }
Radek Krejcidb4e9ff2017-06-13 16:26:14 +0200325 if (index < 0 || !ctx->models.search_paths[0]) {
326 free(ctx->models.search_paths);
327 ctx->models.search_paths = NULL;
328 }
Radek Krejci5a797572015-10-21 15:45:45 +0200329}
330
Michal Vasko60ba9a62015-07-03 14:42:31 +0200331API void
Radek Krejcifa0b5e02016-02-04 13:57:03 +0100332ly_ctx_destroy(struct ly_ctx *ctx, void (*private_destructor)(const struct lys_node *node, void *priv))
Radek Krejcida04f4a2015-05-21 12:54:09 +0200333{
Radek Krejcida9f8392017-03-25 19:40:56 -0500334 int i;
335
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200336 if (!ctx) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200337 return;
338 }
Radek Krejcida04f4a2015-05-21 12:54:09 +0200339
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200340 /* models list */
Radek Krejcic436a232017-02-08 14:43:11 +0100341 for (; ctx->models.used > 0; ctx->models.used--) {
Radek Krejcifc8411a2017-02-03 10:26:05 +0100342 /* remove the applied deviations and augments */
Radek Krejcic436a232017-02-08 14:43:11 +0100343 lys_sub_module_remove_devs_augs(ctx->models.list[ctx->models.used - 1]);
Radek Krejcifc8411a2017-02-03 10:26:05 +0100344 /* remove the module */
Radek Krejcic436a232017-02-08 14:43:11 +0100345 lys_free(ctx->models.list[ctx->models.used - 1], private_destructor, 0);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200346 }
Radek Krejcida9f8392017-03-25 19:40:56 -0500347 if (ctx->models.search_paths) {
348 for(i = 0; ctx->models.search_paths[i]; i++) {
349 free(ctx->models.search_paths[i]);
350 }
351 free(ctx->models.search_paths);
352 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200353 free(ctx->models.list);
Radek Krejcida04f4a2015-05-21 12:54:09 +0200354
Radek Krejcicf748252017-09-04 11:11:14 +0200355 /* clean the error list */
356 ly_err_clean(ctx, 0);
357 pthread_key_delete(ctx->errlist_key);
358
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200359 /* dictionary */
360 lydict_clean(&ctx->dict);
Radek Krejcida04f4a2015-05-21 12:54:09 +0200361
Radek Krejci858ad952017-01-04 11:16:32 +0100362 /* plugins - will be removed only if this is the last context */
363 ext_plugins_ref--;
364 lyext_clean_plugins();
365
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200366 free(ctx);
Radek Krejcida04f4a2015-05-21 12:54:09 +0200367}
368
Michal Vasko1e62a092015-12-01 12:27:20 +0100369API const struct lys_submodule *
Radek Krejci62f0da72016-03-07 11:35:43 +0100370ly_ctx_get_submodule2(const struct lys_module *main_module, const char *submodule)
371{
Radek Krejcid4c1d0f2017-01-19 16:11:38 +0100372 const struct lys_submodule *result;
Radek Krejci62f0da72016-03-07 11:35:43 +0100373 int i;
374
375 if (!main_module || !submodule) {
376 ly_errno = LY_EINVAL;
377 return NULL;
378 }
379
380 /* search in submodules list */
381 for (i = 0; i < main_module->inc_size; i++) {
382 result = main_module->inc[i].submodule;
Radek Krejcid4c1d0f2017-01-19 16:11:38 +0100383 if (ly_strequal(submodule, result->name, 0)) {
Radek Krejci62f0da72016-03-07 11:35:43 +0100384 return result;
385 }
Radek Krejcid4c1d0f2017-01-19 16:11:38 +0100386
387 /* in YANG 1.1 all the submodules must be included in the main module, so we are done.
388 * YANG 1.0 allows (is unclear about denying it) to include a submodule only in another submodule
389 * but when libyang parses such a module it adds the include into the main module so we are also done.
390 */
Radek Krejci62f0da72016-03-07 11:35:43 +0100391 }
392
Radek Krejcid4c1d0f2017-01-19 16:11:38 +0100393
Radek Krejci62f0da72016-03-07 11:35:43 +0100394 return NULL;
395}
396
397API const struct lys_submodule *
Michal Vaskof6d94c62016-04-05 11:21:54 +0200398ly_ctx_get_submodule(const struct ly_ctx *ctx, const char *module, const char *revision, const char *submodule,
399 const char *sub_revision)
Radek Krejciefaeba32015-05-27 14:30:57 +0200400{
Radek Krejcie7973552016-03-07 08:12:01 +0100401 const struct lys_module *mainmod;
Michal Vaskof6d94c62016-04-05 11:21:54 +0200402 const struct lys_submodule *ret = NULL, *submod;
403 uint32_t idx = 0;
Radek Krejciefaeba32015-05-27 14:30:57 +0200404
Michal Vaskof6d94c62016-04-05 11:21:54 +0200405 if (!ctx || !submodule || (revision && !module)) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200406 ly_errno = LY_EINVAL;
407 return NULL;
408 }
Radek Krejciefaeba32015-05-27 14:30:57 +0200409
Michal Vaskof6d94c62016-04-05 11:21:54 +0200410 while ((mainmod = ly_ctx_get_module_iter(ctx, &idx))) {
411 if (module && strcmp(mainmod->name, module)) {
412 /* main module name does not match */
413 continue;
414 }
415
416 if (revision && (!mainmod->rev || strcmp(revision, mainmod->rev[0].date))) {
417 /* main module revision does not match */
418 continue;
419 }
420
421 submod = ly_ctx_get_submodule2(mainmod, submodule);
422 if (!submod) {
423 continue;
424 }
425
426 if (!sub_revision) {
427 /* store only if newer */
428 if (ret) {
429 if (submod->rev && (!ret->rev || (strcmp(submod->rev[0].date, ret->rev[0].date) > 0))) {
430 ret = submod;
431 }
432 } else {
433 ret = submod;
434 }
435 } else {
436 /* store only if revision matches, we are done if it does */
437 if (!submod->rev) {
438 continue;
439 } else if (!strcmp(sub_revision, submod->rev[0].date)) {
440 ret = submod;
441 break;
442 }
443 }
Radek Krejcia7533f22016-03-07 07:37:45 +0100444 }
Radek Krejcic071c542016-01-27 14:57:51 +0100445
Michal Vaskof6d94c62016-04-05 11:21:54 +0200446 return ret;
Radek Krejciefaeba32015-05-27 14:30:57 +0200447}
448
Michal Vasko1e62a092015-12-01 12:27:20 +0100449static const struct lys_module *
Radek Krejci0ec51da2016-12-14 16:42:03 +0100450ly_ctx_get_module_by(const struct ly_ctx *ctx, const char *key, int offset, const char *revision, int with_disabled)
Radek Krejciefaeba32015-05-27 14:30:57 +0200451{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200452 int i;
Radek Krejcib8048692015-08-05 13:36:34 +0200453 struct lys_module *result = NULL;
Radek Krejciefaeba32015-05-27 14:30:57 +0200454
Radek Krejcifd4e6e32015-08-10 15:00:51 +0200455 if (!ctx || !key) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200456 ly_errno = LY_EINVAL;
457 return NULL;
458 }
Radek Krejciefaeba32015-05-27 14:30:57 +0200459
Radek Krejcidce51452015-06-16 15:20:08 +0200460 for (i = 0; i < ctx->models.used; i++) {
Radek Krejci0ec51da2016-12-14 16:42:03 +0100461 if (!with_disabled && ctx->models.list[i]->disabled) {
462 /* skip the disabled modules */
463 continue;
464 }
Radek Krejcifd4e6e32015-08-10 15:00:51 +0200465 /* use offset to get address of the pointer to string (char**), remember that offset is in
466 * bytes, so we have to cast the pointer to the module to (char*), finally, we want to have
467 * string not the pointer to string
468 */
469 if (!ctx->models.list[i] || strcmp(key, *(char**)(((char*)ctx->models.list[i]) + offset))) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200470 continue;
471 }
Radek Krejciefaeba32015-05-27 14:30:57 +0200472
Radek Krejcif647e612015-07-30 11:36:07 +0200473 if (!revision) {
474 /* compare revisons and remember the newest one */
475 if (result) {
476 if (!ctx->models.list[i]->rev_size) {
477 /* the current have no revision, keep the previous with some revision */
478 continue;
479 }
480 if (result->rev_size && strcmp(ctx->models.list[i]->rev[0].date, result->rev[0].date) < 0) {
481 /* the previous found matching module has a newer revision */
482 continue;
483 }
484 }
485
486 /* remember the current match and search for newer version */
487 result = ctx->models.list[i];
488 } else {
489 if (ctx->models.list[i]->rev_size && !strcmp(revision, ctx->models.list[i]->rev[0].date)) {
490 /* matching revision */
Michal Vasko97586502015-08-12 14:32:18 +0200491 result = ctx->models.list[i];
492 break;
Radek Krejcif647e612015-07-30 11:36:07 +0200493 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200494 }
495 }
Radek Krejciefaeba32015-05-27 14:30:57 +0200496
Radek Krejcif647e612015-07-30 11:36:07 +0200497 return result;
Radek Krejcifd4e6e32015-08-10 15:00:51 +0200498
499}
500
Michal Vasko1e62a092015-12-01 12:27:20 +0100501API const struct lys_module *
502ly_ctx_get_module_by_ns(const struct ly_ctx *ctx, const char *ns, const char *revision)
Radek Krejcifd4e6e32015-08-10 15:00:51 +0200503{
Radek Krejci0ec51da2016-12-14 16:42:03 +0100504 return ly_ctx_get_module_by(ctx, ns, offsetof(struct lys_module, ns), revision, 0);
Radek Krejcifd4e6e32015-08-10 15:00:51 +0200505}
506
Michal Vasko1e62a092015-12-01 12:27:20 +0100507API const struct lys_module *
508ly_ctx_get_module(const struct ly_ctx *ctx, const char *name, const char *revision)
Radek Krejcifd4e6e32015-08-10 15:00:51 +0200509{
Radek Krejci0ec51da2016-12-14 16:42:03 +0100510 return ly_ctx_get_module_by(ctx, name, offsetof(struct lys_module, name), revision, 0);
Radek Krejcida04f4a2015-05-21 12:54:09 +0200511}
Michal Vasko3ec07dc2015-06-30 15:51:30 +0200512
Radek Krejci21601a32016-03-07 11:39:27 +0100513API const struct lys_module *
514ly_ctx_get_module_older(const struct ly_ctx *ctx, const struct lys_module *module)
515{
516 int i;
517 const struct lys_module *result = NULL, *iter;
518
519 if (!ctx || !module || !module->rev_size) {
520 ly_errno = LY_EINVAL;
521 return NULL;
522 }
523
524
525 for (i = 0; i < ctx->models.used; i++) {
526 iter = ctx->models.list[i];
Radek Krejci0ec51da2016-12-14 16:42:03 +0100527 if (iter->disabled) {
528 /* skip the disabled modules */
529 continue;
530 }
Radek Krejci21601a32016-03-07 11:39:27 +0100531 if (iter == module || !iter->rev_size) {
532 /* iter is the module itself or iter has no revision */
533 continue;
534 }
535 if (!ly_strequal(module->name, iter->name, 0)) {
536 /* different module */
537 continue;
538 }
539 if (strcmp(iter->rev[0].date, module->rev[0].date) < 0) {
540 /* iter is older than module */
541 if (result) {
542 if (strcmp(iter->rev[0].date, result->rev[0].date) > 0) {
543 /* iter is newer than current result */
544 result = iter;
545 }
546 } else {
547 result = iter;
548 }
549 }
550 }
551
552 return result;
553}
554
Michal Vasko99b0aad2015-12-01 12:28:51 +0100555API void
Michal Vaskoca28aab2017-01-13 13:50:12 +0100556ly_ctx_set_module_imp_clb(struct ly_ctx *ctx, ly_module_imp_clb clb, void *user_data)
Michal Vasko82465962015-11-10 11:03:11 +0100557{
Michal Vaskoad9f92a2017-04-06 09:49:07 +0200558 if (!ctx) {
559 ly_errno = LY_EINVAL;
560 return;
561 }
562
Michal Vaskof53187d2017-01-13 13:23:14 +0100563 ctx->imp_clb = clb;
564 ctx->imp_clb_data = user_data;
Michal Vasko99b0aad2015-12-01 12:28:51 +0100565}
566
Michal Vaskof53187d2017-01-13 13:23:14 +0100567API ly_module_imp_clb
Michal Vaskoca28aab2017-01-13 13:50:12 +0100568ly_ctx_get_module_imp_clb(const struct ly_ctx *ctx, void **user_data)
Michal Vasko99b0aad2015-12-01 12:28:51 +0100569{
Radek Krejciee554172016-12-14 10:29:06 +0100570 if (!ctx) {
571 ly_errno = LY_EINVAL;
572 return NULL;
573 }
574
Michal Vasko99b0aad2015-12-01 12:28:51 +0100575 if (user_data) {
Michal Vaskof53187d2017-01-13 13:23:14 +0100576 *user_data = ctx->imp_clb_data;
Michal Vasko99b0aad2015-12-01 12:28:51 +0100577 }
Michal Vaskof53187d2017-01-13 13:23:14 +0100578 return ctx->imp_clb;
579}
580
581API void
Michal Vaskoca28aab2017-01-13 13:50:12 +0100582ly_ctx_set_module_data_clb(struct ly_ctx *ctx, ly_module_data_clb clb, void *user_data)
Michal Vaskof53187d2017-01-13 13:23:14 +0100583{
Michal Vaskoad9f92a2017-04-06 09:49:07 +0200584 if (!ctx) {
585 ly_errno = LY_EINVAL;
586 return;
587 }
588
Michal Vaskof53187d2017-01-13 13:23:14 +0100589 ctx->data_clb = clb;
590 ctx->data_clb_data = user_data;
591}
592
593API ly_module_data_clb
Michal Vaskoca28aab2017-01-13 13:50:12 +0100594ly_ctx_get_module_data_clb(const struct ly_ctx *ctx, void **user_data)
Michal Vaskof53187d2017-01-13 13:23:14 +0100595{
Michal Vaskoad9f92a2017-04-06 09:49:07 +0200596 if (!ctx) {
597 ly_errno = LY_EINVAL;
598 return NULL;
599 }
600
Michal Vaskof53187d2017-01-13 13:23:14 +0100601 if (user_data) {
602 *user_data = ctx->data_clb_data;
603 }
604 return ctx->data_clb;
Michal Vasko99b0aad2015-12-01 12:28:51 +0100605}
606
Radek Krejcibf4e4652016-10-21 15:44:13 +0200607const struct lys_module *
Michal Vasko84475152016-07-25 16:16:25 +0200608ly_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 +0200609 int implement, struct unres_schema *unres)
Michal Vasko99b0aad2015-12-01 12:28:51 +0100610{
Radek Krejcibf4e4652016-10-21 15:44:13 +0200611 const struct lys_module *mod;
Michal Vasko99b0aad2015-12-01 12:28:51 +0100612 char *module_data;
Radek Krejci03203412016-06-23 15:20:53 +0200613 int i;
Michal Vaskod3e975b2016-03-03 15:40:21 +0100614 void (*module_data_free)(void *module_data) = NULL;
Michal Vasko99b0aad2015-12-01 12:28:51 +0100615 LYS_INFORMAT format = LYS_IN_UNKNOWN;
Michal Vasko82465962015-11-10 11:03:11 +0100616
Michal Vasko84475152016-07-25 16:16:25 +0200617 if (!module) {
Radek Krejcibf4e4652016-10-21 15:44:13 +0200618 /* exception for internal modules */
Michal Vasko2d051a12017-04-21 09:28:57 +0200619 for (i = 0; i < LY_INTERNAL_MODULE_COUNT; i++) {
Michal Vasko84475152016-07-25 16:16:25 +0200620 if (ly_strequal(name, internal_modules[i].name, 0)) {
621 if (!revision || ly_strequal(revision, internal_modules[i].revision, 0)) {
622 /* return internal module */
623 return (struct lys_module *)ly_ctx_get_module(ctx, name, revision);
624 }
Radek Krejci03203412016-06-23 15:20:53 +0200625 }
626 }
Radek Krejcibf4e4652016-10-21 15:44:13 +0200627 if (revision) {
Radek Krejci0ec51da2016-12-14 16:42:03 +0100628 /* try to get the schema with the specific revision from the context,
629 * include the disabled modules in the search to avoid their duplication,
630 * they are enabled by the subsequent call to lys_set_implemented() */
Michal Vasko2d051a12017-04-21 09:28:57 +0200631 for (i = LY_INTERNAL_MODULE_COUNT, mod = NULL; i < ctx->models.used; i++) {
Radek Krejci0ec51da2016-12-14 16:42:03 +0100632 mod = ctx->models.list[i]; /* shortcut */
633 if (ly_strequal(name, mod->name, 0) && mod->rev_size && !strcmp(revision, mod->rev[0].date)) {
634 break;
635 }
636 mod = NULL;
637 }
Radek Krejcibf4e4652016-10-21 15:44:13 +0200638 if (mod) {
639 /* we get such a module, make it implemented */
640 if (lys_set_implemented(mod)) {
641 /* the schema cannot be implemented */
642 mod = NULL;
643 }
644 return mod;
645 }
646 }
Radek Krejci03203412016-06-23 15:20:53 +0200647 }
648
Michal Vaskof53187d2017-01-13 13:23:14 +0100649 if (ctx->imp_clb) {
Michal Vasko84475152016-07-25 16:16:25 +0200650 if (module) {
651 mod = lys_main_module(module);
Michal Vaskof53187d2017-01-13 13:23:14 +0100652 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 +0200653 } else {
Michal Vaskof53187d2017-01-13 13:23:14 +0100654 module_data = ctx->imp_clb(name, revision, NULL, NULL, ctx->imp_clb_data, &format, &module_data_free);
Michal Vasko84475152016-07-25 16:16:25 +0200655 }
Michal Vasko99b0aad2015-12-01 12:28:51 +0100656 if (!module_data) {
Radek Krejcibf4e4652016-10-21 15:44:13 +0200657 if (module || revision) {
658 /* we already know that the specified revision is not present in context, and we have no other
659 * option in case of submodules */
660 LOGERR(LY_ESYS, "User module retrieval callback failed!");
661 return NULL;
662 } else {
663 /* get the newest revision from the context */
Radek Krejci0ec51da2016-12-14 16:42:03 +0100664 mod = ly_ctx_get_module_by(ctx, name, offsetof(struct lys_module, name), revision, 1);
665 if (mod && mod->disabled) {
666 /* enable the required module */
667 lys_set_enabled(mod);
668 }
669 return mod;
Radek Krejcibf4e4652016-10-21 15:44:13 +0200670 }
Michal Vasko82465962015-11-10 11:03:11 +0100671 }
Michal Vasko84475152016-07-25 16:16:25 +0200672
673 if (module) {
Michal Vasko5b998712017-01-26 10:34:06 +0100674 mod = (struct lys_module *)lys_sub_parse_mem(module, module_data, format, unres);
Michal Vasko84475152016-07-25 16:16:25 +0200675 } else {
Michal Vasko29245662017-04-18 15:56:31 +0200676 mod = (struct lys_module *)lys_parse_mem_(ctx, module_data, format, 0, implement);
Michal Vasko84475152016-07-25 16:16:25 +0200677 }
678
Michal Vasko99b0aad2015-12-01 12:28:51 +0100679 if (module_data_free) {
680 module_data_free(module_data);
Michal Vasko82465962015-11-10 11:03:11 +0100681 }
Michal Vasko99b0aad2015-12-01 12:28:51 +0100682 } else {
Michal Vasko58e5f3e2016-07-28 11:06:34 +0200683 mod = lyp_search_file(ctx, module, name, revision, implement, unres);
Michal Vasko82465962015-11-10 11:03:11 +0100684 }
685
Michal Vasko84475152016-07-25 16:16:25 +0200686 return mod;
687}
688
689API const struct lys_module *
690ly_ctx_load_module(struct ly_ctx *ctx, const char *name, const char *revision)
691{
692 if (!ctx || !name) {
693 ly_errno = LY_EINVAL;
694 return NULL;
695 }
696
Radek Krejci05f15982017-06-13 15:26:10 +0200697 return ly_ctx_load_sub_module(ctx, NULL, name, revision && revision[0] ? revision : NULL, 1, NULL);
Michal Vasko82465962015-11-10 11:03:11 +0100698}
699
Radek Krejci85a54be2016-10-20 12:39:56 +0200700/*
701 * mods - set of removed modules, if NULL all modules are supposed to be removed so any backlink is invalid
702 */
Michal Vasko4be5fa22017-02-07 10:12:32 +0100703static void
704ctx_modules_undo_backlinks(struct ly_ctx *ctx, struct ly_set *mods)
Radek Krejci85a54be2016-10-20 12:39:56 +0200705{
706 int o;
707 uint8_t j;
708 unsigned int u, v;
709 struct lys_module *mod;
710 struct lys_node *elem, *next;
711 struct lys_node_leaf *leaf;
712
713 /* maintain backlinks (start with internal ietf-yang-library which have leafs as possible targets of leafrefs */
Michal Vasko2d051a12017-04-21 09:28:57 +0200714 for (o = LY_INTERNAL_MODULE_COUNT - 1; o < ctx->models.used; o++) {
Radek Krejci85a54be2016-10-20 12:39:56 +0200715 mod = ctx->models.list[o]; /* shortcut */
716
717 /* 1) features */
718 for (j = 0; j < mod->features_size; j++) {
719 if (!mod->features[j].depfeatures) {
720 continue;
721 }
722 for (v = 0; v < mod->features[j].depfeatures->number; v++) {
723 if (!mods || ly_set_contains(mods, ((struct lys_feature *)mod->features[j].depfeatures->set.g[v])->module) != -1) {
724 /* depending feature is in module to remove */
725 ly_set_rm_index(mod->features[j].depfeatures, v);
726 v--;
727 }
728 }
729 if (!mod->features[j].depfeatures->number) {
730 /* all backlinks removed */
731 ly_set_free(mod->features[j].depfeatures);
732 mod->features[j].depfeatures = NULL;
733 }
734 }
Michal Vasko4be5fa22017-02-07 10:12:32 +0100735
736 /* 2) identities */
Radek Krejci85a54be2016-10-20 12:39:56 +0200737 for (u = 0; u < mod->ident_size; u++) {
738 if (!mod->ident[u].der) {
739 continue;
740 }
741 for (v = 0; v < mod->ident[u].der->number; v++) {
742 if (!mods || ly_set_contains(mods, ((struct lys_ident *)mod->ident[u].der->set.g[v])->module) != -1) {
743 /* derived identity is in module to remove */
744 ly_set_rm_index(mod->ident[u].der, v);
745 v--;
746 }
747 }
748 if (!mod->ident[u].der->number) {
749 /* all backlinks removed */
750 ly_set_free(mod->ident[u].der);
751 mod->ident[u].der = NULL;
752 }
753 }
754
Michal Vasko4be5fa22017-02-07 10:12:32 +0100755 /* 3) leafrefs */
Radek Krejci85a54be2016-10-20 12:39:56 +0200756 for (elem = next = mod->data; elem; elem = next) {
757 if (elem->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
758 leaf = (struct lys_node_leaf *)elem; /* shortcut */
759 if (leaf->backlinks) {
760 if (!mods) {
761 /* remove all backlinks */
762 ly_set_free(leaf->backlinks);
763 leaf->backlinks = NULL;
764 } else {
765 for (v = 0; v < leaf->backlinks->number; v++) {
766 if (ly_set_contains(mods, leaf->backlinks->set.s[v]->module) != -1) {
767 /* derived identity is in module to remove */
768 ly_set_rm_index(leaf->backlinks, v);
769 v--;
770 }
771 }
772 if (!leaf->backlinks->number) {
773 /* all backlinks removed */
774 ly_set_free(leaf->backlinks);
775 leaf->backlinks = NULL;
776 }
777 }
778 }
779 }
780
781 /* select next element to process */
782 next = elem->child;
783 /* child exception for leafs, leaflists, anyxml and groupings */
784 if (elem->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA | LYS_GROUPING)) {
785 next = NULL;
786 }
787 if (!next) {
788 /* no children, try siblings */
789 next = elem->next;
790 }
791 while (!next) {
792 /* parent is already processed, go to its sibling */
793 elem = lys_parent(elem);
794 if (!elem) {
795 /* we are done, no next element to process */
796 break;
797 }
798 /* no siblings, go back through parents */
799 next = elem->next;
800 }
801 }
802 }
Michal Vasko4be5fa22017-02-07 10:12:32 +0100803}
Radek Krejci85a54be2016-10-20 12:39:56 +0200804
Michal Vasko4be5fa22017-02-07 10:12:32 +0100805static int
Radek Krejci83a4bac2017-02-07 15:53:04 +0100806ctx_modules_redo_backlinks(struct ly_set *mods)
Michal Vasko4be5fa22017-02-07 10:12:32 +0100807{
Radek Krejci83a4bac2017-02-07 15:53:04 +0100808 unsigned int i, j, k, s;
809 struct lys_module *mod;
810 struct lys_node *next, *elem;
811 struct lys_type *type;
812 struct lys_feature *feat;
Michal Vasko4be5fa22017-02-07 10:12:32 +0100813
Michal Vasko4be5fa22017-02-07 10:12:32 +0100814 for (i = 0; i < mods->number; ++i) {
Radek Krejci83a4bac2017-02-07 15:53:04 +0100815 mod = (struct lys_module *)mods->set.g[i]; /* shortcut */
Michal Vasko4be5fa22017-02-07 10:12:32 +0100816
Radek Krejci83a4bac2017-02-07 15:53:04 +0100817 /* identities */
Radek Krejci9e6af732017-04-27 14:40:25 +0200818 if (mod->implemented) {
819 for (j = 0; j < mod->ident_size; j++) {
820 for (k = 0; k < mod->ident[j].base_size; k++) {
821 resolve_identity_backlink_update(&mod->ident[j], mod->ident[j].base[k]);
822 }
Radek Krejci83a4bac2017-02-07 15:53:04 +0100823 }
824 }
Michal Vasko4be5fa22017-02-07 10:12:32 +0100825
Radek Krejci83a4bac2017-02-07 15:53:04 +0100826 /* features */
827 for (j = 0; j < mod->features_size; j++) {
828 for (k = 0; k < mod->features[j].iffeature_size; k++) {
829 resolve_iffeature_getsizes(&mod->features[j].iffeature[k], NULL, &s);
830 while (s--) {
831 feat = mod->features[j].iffeature[k].features[s]; /* shortcut */
832 if (!feat->depfeatures) {
833 feat->depfeatures = ly_set_new();
834 }
835 ly_set_add(feat->depfeatures, &mod->features[j], LY_SET_OPT_USEASLIST);
836 }
837 }
838 }
839
840 /* leafrefs */
841 LY_TREE_DFS_BEGIN(mod->data, next, elem) {
Michal Vaskofa3d2f72017-04-10 13:30:44 +0200842 if (elem->nodetype == LYS_GROUPING) {
843 goto next_sibling;
844 }
845
Radek Krejci83a4bac2017-02-07 15:53:04 +0100846 if (elem->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
847 type = &((struct lys_node_leaf *)elem)->type; /* shortcut */
848 if (type->base == LY_TYPE_LEAFREF) {
849 lys_leaf_add_leafref_target(type->info.lref.target, elem);
850 }
851 }
852
Michal Vaskofa3d2f72017-04-10 13:30:44 +0200853 /* select element for the next run - children first */
854 next = elem->child;
855
856 /* child exception for leafs, leaflists and anyxml without children */
857 if (elem->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
858 next = NULL;
859 }
860 if (!next) {
861next_sibling:
862 /* no children */
863 if (elem == mod->data) {
864 /* we are done, (START) has no children */
865 break;
866 }
867 /* try siblings */
868 next = elem->next;
869 }
870 while (!next) {
871 /* parent is already processed, go to its sibling */
872 elem = lys_parent(elem);
873
874 /* no siblings, go back through parents */
875 if (lys_parent(elem) == lys_parent(mod->data)) {
876 /* we are done, no next element to process */
877 break;
878 }
879 next = elem->next;
880 }
Radek Krejci83a4bac2017-02-07 15:53:04 +0100881 }
Michal Vasko4be5fa22017-02-07 10:12:32 +0100882 }
883
884 return 0;
Radek Krejci85a54be2016-10-20 12:39:56 +0200885}
886
Radek Krejci8c107fe2016-10-17 16:00:18 +0200887API int
Radek Krejci0ec51da2016-12-14 16:42:03 +0100888lys_set_disabled(const struct lys_module *module)
889{
890 struct ly_ctx *ctx; /* shortcut */
891 struct lys_module *mod;
892 struct ly_set *mods;
893 uint8_t j, imported;
894 int i, o;
Radek Krejci29eac3d2017-06-01 16:50:02 +0200895 unsigned int u, v;
Radek Krejci0ec51da2016-12-14 16:42:03 +0100896
897 if (!module) {
898 ly_errno = LY_EINVAL;
899 return EXIT_FAILURE;
900 } else if (module->disabled) {
901 /* already disabled module */
902 return EXIT_SUCCESS;
903 }
904 mod = (struct lys_module *)module;
905 ctx = mod->ctx;
906
907 /* avoid disabling internal modules */
Michal Vasko2d051a12017-04-21 09:28:57 +0200908 for (i = 0; i < LY_INTERNAL_MODULE_COUNT; i++) {
Radek Krejci0ec51da2016-12-14 16:42:03 +0100909 if (mod == ctx->models.list[i]) {
Michal Vasko2d051a12017-04-21 09:28:57 +0200910 LOGERR(LY_EINVAL, "Internal module \"%s\" cannot be disabled.", mod->name);
Radek Krejci0ec51da2016-12-14 16:42:03 +0100911 return EXIT_FAILURE;
912 }
913 }
914
915 /* disable the module */
916 mod->disabled = 1;
917
918 /* get the complete list of modules to disable because of dependencies,
919 * we are going also to disable all the imported (not implemented) modules
920 * that are not used in any other module */
921 mods = ly_set_new();
922 ly_set_add(mods, mod, 0);
923checkdependency:
Michal Vasko2d051a12017-04-21 09:28:57 +0200924 for (i = LY_INTERNAL_MODULE_COUNT; i < ctx->models.used; i++) {
Radek Krejci0ec51da2016-12-14 16:42:03 +0100925 mod = ctx->models.list[i]; /* shortcut */
926 if (mod->disabled) {
927 /* skip the already disabled modules */
928 continue;
929 }
930
931 /* check depndency of imported modules */
932 for (j = 0; j < mod->imp_size; j++) {
933 for (u = 0; u < mods->number; u++) {
934 if (mod->imp[j].module == mods->set.g[u]) {
935 /* module is importing some module to disable, so it must be also disabled */
936 mod->disabled = 1;
937 ly_set_add(mods, mod, 0);
938 /* we have to start again because some of the already checked modules can
939 * depend on the one we have just decided to disable */
940 goto checkdependency;
941 }
942 }
943 }
944 /* check if the imported module is used in any module supposed to be kept */
945 if (!mod->implemented) {
946 imported = 0;
Michal Vasko2d051a12017-04-21 09:28:57 +0200947 for (o = LY_INTERNAL_MODULE_COUNT; o < ctx->models.used; o++) {
Radek Krejci0ec51da2016-12-14 16:42:03 +0100948 if (ctx->models.list[o]->disabled) {
949 /* skip modules already disabled */
950 continue;
951 }
952 for (j = 0; j < ctx->models.list[o]->imp_size; j++) {
953 if (ctx->models.list[o]->imp[j].module == mod) {
954 /* the module is used in some other module not yet selected to be disabled */
955 imported = 1;
956 goto imported;
957 }
958 }
959 }
960imported:
961 if (!imported) {
962 /* module is not implemented and neither imported by any other module in context
963 * which is supposed to be kept enabled after this operation, so we are going to disable also
964 * this module */
965 mod->disabled = 1;
966 ly_set_add(mods, mod, 0);
967 /* we have to start again, this time not because other module can depend on this one
968 * (we know that there is no such module), but because the module can import module
969 * that could became useless. If there are no imports, we can continue */
970 if (mod->imp_size) {
971 goto checkdependency;
972 }
973 }
974 }
975 }
976
977 /* before removing applied deviations, augments and updating leafrefs, we have to enable the modules
978 * to disable to allow all that operations */
979 for (u = 0; u < mods->number; u++) {
980 ((struct lys_module *)mods->set.g[u])->disabled = 0;
981 }
982
983 /* maintain backlinks (start with internal ietf-yang-library which have leafs as possible targets of leafrefs */
Michal Vasko4be5fa22017-02-07 10:12:32 +0100984 ctx_modules_undo_backlinks(ctx, mods);
Radek Krejci0ec51da2016-12-14 16:42:03 +0100985
986 /* remove the applied deviations and augments */
987 for (u = 0; u < mods->number; u++) {
988 lys_sub_module_remove_devs_augs((struct lys_module *)mods->set.g[u]);
989 }
990
Radek Krejci29eac3d2017-06-01 16:50:02 +0200991 /* now again disable the modules to disable and disable also all its submodules */
Radek Krejci0ec51da2016-12-14 16:42:03 +0100992 for (u = 0; u < mods->number; u++) {
Radek Krejci29eac3d2017-06-01 16:50:02 +0200993 mod = (struct lys_module *)mods->set.g[u];
994 mod->disabled = 1;
995 for (v = 0; v < mod->inc_size; v++) {
996 mod->inc[v].submodule->disabled = 1;
997 }
Radek Krejci0ec51da2016-12-14 16:42:03 +0100998 }
999
1000 /* free the set */
1001 ly_set_free(mods);
1002
1003 /* update the module-set-id */
1004 ctx->models.module_set_id++;
1005
1006 return EXIT_SUCCESS;
1007}
1008
1009static void
1010lys_set_enabled_(struct ly_set *mods, struct lys_module *mod)
1011{
1012 unsigned int i;
1013
1014 ly_set_add(mods, mod, 0);
1015 mod->disabled = 0;
1016
Radek Krejci29eac3d2017-06-01 16:50:02 +02001017 for (i = 0; i < mod->inc_size; i++) {
1018 mod->inc[i].submodule->disabled = 0;
1019 }
1020
Radek Krejci0ec51da2016-12-14 16:42:03 +01001021 /* go recursively */
1022 for (i = 0; i < mod->imp_size; i++) {
1023 if (!mod->imp[i].module->disabled) {
1024 continue;
1025 }
1026
1027 lys_set_enabled_(mods, mod->imp[i].module);
1028 }
1029}
1030
1031API int
1032lys_set_enabled(const struct lys_module *module)
1033{
1034 struct ly_ctx *ctx; /* shortcut */
1035 struct lys_module *mod;
1036 struct ly_set *mods, *disabled;
1037 int i;
Radek Krejci29eac3d2017-06-01 16:50:02 +02001038 unsigned int u, v, w;
Radek Krejci0ec51da2016-12-14 16:42:03 +01001039
1040 if (!module) {
1041 ly_errno = LY_EINVAL;
1042 return EXIT_FAILURE;
1043 } else if (!module->disabled) {
1044 /* already enabled module */
1045 return EXIT_SUCCESS;
1046 }
1047 mod = (struct lys_module *)module;
1048 ctx = mod->ctx;
1049
1050 /* avoid disabling internal modules */
Michal Vasko2d051a12017-04-21 09:28:57 +02001051 for (i = 0; i < LY_INTERNAL_MODULE_COUNT; i++) {
Radek Krejci0ec51da2016-12-14 16:42:03 +01001052 if (mod == ctx->models.list[i]) {
1053 LOGERR(LY_EINVAL, "Internal module \"%s\" cannot be removed.", mod->name);
1054 return EXIT_FAILURE;
1055 }
1056 }
1057
1058 mods = ly_set_new();
1059 disabled = ly_set_new();
1060
1061 /* enable the module, including its dependencies */
1062 lys_set_enabled_(mods, mod);
1063
1064 /* we will go through the all disabled modules in the context, if the module has no dependency (import)
1065 * that is still disabled AND at least one of its imported module is from the set we are enabling now,
1066 * it is going to be also enabled. This way we try to revert everething that was possibly done by
1067 * lys_set_disabled(). */
1068checkdependency:
Michal Vasko2d051a12017-04-21 09:28:57 +02001069 for (i = LY_INTERNAL_MODULE_COUNT; i < ctx->models.used; i++) {
Radek Krejci0ec51da2016-12-14 16:42:03 +01001070 mod = ctx->models.list[i]; /* shortcut */
1071 if (!mod->disabled || ly_set_contains(disabled, mod) != -1) {
1072 /* skip the enabled modules */
1073 continue;
1074 }
1075
1076 /* check imported modules */
1077 for (u = 0; u < mod->imp_size; u++) {
1078 if (mod->imp[u].module->disabled) {
1079 /* it has disabled dependency so it must stay disabled */
1080 break;
1081 }
1082 }
1083 if (u < mod->imp_size) {
1084 /* it has disabled dependency, continue with the next module in the context */
1085 continue;
1086 }
1087
1088 /* get know if at least one of the imported modules is being enabled this time */
1089 for (u = 0; u < mod->imp_size; u++) {
1090 for (v = 0; v < mods->number; v++) {
1091 if (mod->imp[u].module == mods->set.g[v]) {
1092 /* yes, it is, so they are connected and we are going to enable it as well,
1093 * it is not necessary to call recursive lys_set_enable_() because we already
1094 * know that there is no disabled import to enable */
1095 mod->disabled = 0;
1096 ly_set_add(mods, mod, 0);
Radek Krejci29eac3d2017-06-01 16:50:02 +02001097 for (w = 0; w < mod->inc_size; w++) {
1098 mod->inc[w].submodule->disabled = 0;
1099 }
Radek Krejci0ec51da2016-12-14 16:42:03 +01001100 /* we have to start again because some of the already checked modules can
1101 * depend on the one we have just decided to enable */
1102 goto checkdependency;
1103 }
1104 }
1105 }
1106
1107 /* this module is disabled, but it does not depend on any other disabled module and none
1108 * of its imports was not enabled in this call. No future enabling of the disabled module
1109 * will change this so we can remember the module and skip it next time we will have to go
1110 * through the all context because of the checkdependency goto.
1111 */
1112 ly_set_add(disabled, mod, 0);
1113 }
1114
1115 /* maintain backlinks (start with internal ietf-yang-library which have leafs as possible targets of leafrefs */
Radek Krejci83a4bac2017-02-07 15:53:04 +01001116 ctx_modules_redo_backlinks(mods);
Radek Krejci0ec51da2016-12-14 16:42:03 +01001117
1118 /* re-apply the deviations and augments */
1119 for (v = 0; v < mods->number; v++) {
1120 lys_sub_module_apply_devs_augs((struct lys_module *)mods->set.g[v]);
1121 }
1122
1123 /* free the sets */
1124 ly_set_free(mods);
1125 ly_set_free(disabled);
1126
1127 /* update the module-set-id */
1128 ctx->models.module_set_id++;
1129
1130 return EXIT_SUCCESS;
1131}
1132
1133API int
1134ly_ctx_remove_module(const struct lys_module *module,
Radek Krejci8c107fe2016-10-17 16:00:18 +02001135 void (*private_destructor)(const struct lys_node *node, void *priv))
1136{
Radek Krejci0ec51da2016-12-14 16:42:03 +01001137 struct ly_ctx *ctx; /* shortcut */
Radek Krejci8c107fe2016-10-17 16:00:18 +02001138 struct lys_module *mod = NULL;
1139 struct ly_set *mods;
1140 uint8_t j, imported;
1141 int i, o;
1142 unsigned int u;
1143
Radek Krejci0ec51da2016-12-14 16:42:03 +01001144 if (!module) {
Radek Krejci8c107fe2016-10-17 16:00:18 +02001145 ly_errno = LY_EINVAL;
1146 return EXIT_FAILURE;
1147 }
1148
Radek Krejci0ec51da2016-12-14 16:42:03 +01001149 mod = (struct lys_module *)module;
1150 ctx = mod->ctx;
1151
Radek Krejci8c107fe2016-10-17 16:00:18 +02001152 /* avoid removing internal modules ... */
Michal Vasko2d051a12017-04-21 09:28:57 +02001153 for (i = 0; i < LY_INTERNAL_MODULE_COUNT; i++) {
Radek Krejci8c107fe2016-10-17 16:00:18 +02001154 if (mod == ctx->models.list[i]) {
Radek Krejci0ec51da2016-12-14 16:42:03 +01001155 LOGERR(LY_EINVAL, "Internal module \"%s\" cannot be removed.", mod->name);
Radek Krejci8c107fe2016-10-17 16:00:18 +02001156 return EXIT_FAILURE;
1157 }
1158 }
1159 /* ... and hide the module from the further processing of the context modules list */
Michal Vasko2d051a12017-04-21 09:28:57 +02001160 for (i = LY_INTERNAL_MODULE_COUNT; i < ctx->models.used; i++) {
Radek Krejci8c107fe2016-10-17 16:00:18 +02001161 if (mod == ctx->models.list[i]) {
1162 ctx->models.list[i] = NULL;
1163 break;
1164 }
1165 }
1166
1167 /* get the complete list of modules to remove because of dependencies,
1168 * we are going also to remove all the imported (not implemented) modules
1169 * that are not used in any other module */
1170 mods = ly_set_new();
1171 ly_set_add(mods, mod, 0);
1172checkdependency:
Michal Vasko2d051a12017-04-21 09:28:57 +02001173 for (i = LY_INTERNAL_MODULE_COUNT; i < ctx->models.used; i++) {
Radek Krejci8c107fe2016-10-17 16:00:18 +02001174 mod = ctx->models.list[i]; /* shortcut */
1175 if (!mod) {
1176 /* skip modules already selected for removing */
1177 continue;
1178 }
1179
1180 /* check depndency of imported modules */
1181 for (j = 0; j < mod->imp_size; j++) {
1182 for (u = 0; u < mods->number; u++) {
1183 if (mod->imp[j].module == mods->set.g[u]) {
1184 /* module is importing some module to remove, so it must be also removed */
1185 ly_set_add(mods, mod, 0);
1186 ctx->models.list[i] = NULL;
1187 /* we have to start again because some of the already checked modules can
1188 * depend on the one we have just decided to remove */
1189 goto checkdependency;
1190 }
1191 }
1192 }
1193 /* check if the imported module is used in any module supposed to be kept */
1194 if (!mod->implemented) {
1195 imported = 0;
Michal Vasko2d051a12017-04-21 09:28:57 +02001196 for (o = LY_INTERNAL_MODULE_COUNT; o < ctx->models.used; o++) {
Radek Krejci8c107fe2016-10-17 16:00:18 +02001197 if (!ctx->models.list[o]) {
1198 /* skip modules already selected for removing */
1199 continue;
1200 }
1201 for (j = 0; j < ctx->models.list[o]->imp_size; j++) {
1202 if (ctx->models.list[o]->imp[j].module == mod) {
1203 /* the module is used in some other module not yet selected to be deleted */
1204 imported = 1;
1205 goto imported;
1206 }
1207 }
1208 }
1209imported:
1210 if (!imported) {
1211 /* module is not implemented and neither imported by any other module in context
1212 * which is supposed to be kept after this operation, so we are going to remove also
1213 * this useless module */
1214 ly_set_add(mods, mod, 0);
1215 ctx->models.list[i] = NULL;
1216 /* we have to start again, this time not because other module can depend on this one
Radek Krejci0ec51da2016-12-14 16:42:03 +01001217 * (we know that there is no such module), but because the module can import module
Radek Krejci8c107fe2016-10-17 16:00:18 +02001218 * that could became useless. If there are no imports, we can continue */
1219 if (mod->imp_size) {
1220 goto checkdependency;
1221 }
1222 }
1223 }
1224 }
1225
Radek Krejci8c107fe2016-10-17 16:00:18 +02001226
1227 /* consolidate the modules list */
Michal Vasko2d051a12017-04-21 09:28:57 +02001228 for (i = o = LY_INTERNAL_MODULE_COUNT; i < ctx->models.used; i++) {
Radek Krejci8c107fe2016-10-17 16:00:18 +02001229 if (ctx->models.list[o]) {
1230 /* used cell */
1231 o++;
1232 } else {
1233 /* the current output cell is empty, move here an input cell */
1234 ctx->models.list[o] = ctx->models.list[i];
1235 ctx->models.list[i] = NULL;
1236 }
1237 }
1238 /* get the last used cell to get know the number of used */
1239 while (!ctx->models.list[o]) {
1240 o--;
1241 }
1242 ctx->models.used = o + 1;
1243 ctx->models.module_set_id++;
1244
Radek Krejci85a54be2016-10-20 12:39:56 +02001245 /* maintain backlinks (start with internal ietf-yang-library which have leafs as possible targets of leafrefs */
Michal Vasko4be5fa22017-02-07 10:12:32 +01001246 ctx_modules_undo_backlinks(ctx, mods);
Radek Krejci85a54be2016-10-20 12:39:56 +02001247
1248 /* free the modules */
1249 for (u = 0; u < mods->number; u++) {
Radek Krejcib2541a32016-12-12 16:45:57 +01001250 /* remove the applied deviations and augments */
1251 lys_sub_module_remove_devs_augs((struct lys_module *)mods->set.g[u]);
Radek Krejci85a54be2016-10-20 12:39:56 +02001252 /* remove the module */
1253 lys_free((struct lys_module *)mods->set.g[u], private_destructor, 0);
1254 }
1255 ly_set_free(mods);
1256
Radek Krejci8c107fe2016-10-17 16:00:18 +02001257 return EXIT_SUCCESS;
1258}
1259
Radek Krejci85a54be2016-10-20 12:39:56 +02001260API void
1261ly_ctx_clean(struct ly_ctx *ctx, void (*private_destructor)(const struct lys_node *node, void *priv))
1262{
Radek Krejci85a54be2016-10-20 12:39:56 +02001263 if (!ctx) {
1264 return;
1265 }
1266
1267 /* models list */
Michal Vasko2d051a12017-04-21 09:28:57 +02001268 for (; ctx->models.used > LY_INTERNAL_MODULE_COUNT; ctx->models.used--) {
Radek Krejcifc8411a2017-02-03 10:26:05 +01001269 /* remove the applied deviations and augments */
Radek Krejcic436a232017-02-08 14:43:11 +01001270 lys_sub_module_remove_devs_augs(ctx->models.list[ctx->models.used - 1]);
Radek Krejcifc8411a2017-02-03 10:26:05 +01001271 /* remove the module */
Radek Krejcic436a232017-02-08 14:43:11 +01001272 lys_free(ctx->models.list[ctx->models.used - 1], private_destructor, 0);
Radek Krejcifc8411a2017-02-03 10:26:05 +01001273 /* clean it for safer future use */
Radek Krejcic436a232017-02-08 14:43:11 +01001274 ctx->models.list[ctx->models.used - 1] = NULL;
Radek Krejci85a54be2016-10-20 12:39:56 +02001275 }
Radek Krejci85a54be2016-10-20 12:39:56 +02001276 ctx->models.module_set_id++;
1277
Radek Krejci83a4bac2017-02-07 15:53:04 +01001278 /* maintain backlinks (actually done only with ietf-yang-library since its leafs can be target of leafref) */
Michal Vasko4be5fa22017-02-07 10:12:32 +01001279 ctx_modules_undo_backlinks(ctx, NULL);
Radek Krejci85a54be2016-10-20 12:39:56 +02001280}
1281
Michal Vaskod7957c02016-04-01 10:27:26 +02001282API const struct lys_module *
1283ly_ctx_get_module_iter(const struct ly_ctx *ctx, uint32_t *idx)
1284{
1285 if (!ctx || !idx) {
1286 ly_errno = LY_EINVAL;
1287 return NULL;
1288 }
1289
Radek Krejci0ec51da2016-12-14 16:42:03 +01001290 for ( ; *idx < (unsigned)ctx->models.used; (*idx)++) {
1291 if (!ctx->models.list[(*idx)]->disabled) {
1292 return ctx->models.list[(*idx)++];
1293 }
1294 }
1295
1296 return NULL;
1297}
1298
1299API const struct lys_module *
1300ly_ctx_get_disabled_module_iter(const struct ly_ctx *ctx, uint32_t *idx)
1301{
1302 if (!ctx || !idx) {
1303 ly_errno = LY_EINVAL;
Michal Vaskod7957c02016-04-01 10:27:26 +02001304 return NULL;
1305 }
1306
Radek Krejci0ec51da2016-12-14 16:42:03 +01001307 for ( ; *idx < (unsigned)ctx->models.used; (*idx)++) {
1308 if (ctx->models.list[(*idx)]->disabled) {
1309 return ctx->models.list[(*idx)++];
1310 }
1311 }
1312
1313 return NULL;
Michal Vaskod7957c02016-04-01 10:27:26 +02001314}
1315
Michal Vasko209a6222015-10-16 09:51:07 +02001316static int
1317ylib_feature(struct lyd_node *parent, struct lys_module *cur_mod)
1318{
1319 int i, j;
1320
1321 /* module features */
1322 for (i = 0; i < cur_mod->features_size; ++i) {
1323 if (!(cur_mod->features[i].flags & LYS_FENABLED)) {
1324 continue;
1325 }
1326
Michal Vasko3e671b52015-10-23 16:23:15 +02001327 if (!lyd_new_leaf(parent, NULL, "feature", cur_mod->features[i].name)) {
Michal Vasko209a6222015-10-16 09:51:07 +02001328 return EXIT_FAILURE;
1329 }
1330 }
1331
1332 /* submodule features */
Radek Krejcic071c542016-01-27 14:57:51 +01001333 for (i = 0; i < cur_mod->inc_size && cur_mod->inc[i].submodule; ++i) {
Michal Vasko209a6222015-10-16 09:51:07 +02001334 for (j = 0; j < cur_mod->inc[i].submodule->features_size; ++j) {
1335 if (!(cur_mod->inc[i].submodule->features[j].flags & LYS_FENABLED)) {
1336 continue;
1337 }
1338
Michal Vasko3e671b52015-10-23 16:23:15 +02001339 if (!lyd_new_leaf(parent, NULL, "feature", cur_mod->inc[i].submodule->features[j].name)) {
Michal Vasko209a6222015-10-16 09:51:07 +02001340 return EXIT_FAILURE;
1341 }
1342 }
1343 }
1344
1345 return EXIT_SUCCESS;
1346}
1347
1348static int
Michal Vaskoff006c12016-02-17 11:15:19 +01001349ylib_deviation(struct lyd_node *parent, struct lys_module *cur_mod)
Michal Vasko97d8c6d2016-02-12 11:05:48 +01001350{
Michal Vasko89563fc2016-07-28 16:19:35 +02001351 uint32_t i = 0, j;
1352 const struct lys_module *mod;
Michal Vasko209a6222015-10-16 09:51:07 +02001353 struct lyd_node *cont;
Michal Vasko89563fc2016-07-28 16:19:35 +02001354 const char *ptr;
Michal Vasko209a6222015-10-16 09:51:07 +02001355
Michal Vasko89563fc2016-07-28 16:19:35 +02001356 if (cur_mod->deviated) {
1357 while ((mod = ly_ctx_get_module_iter(cur_mod->ctx, &i))) {
1358 if (mod == cur_mod) {
1359 continue;
Michal Vasko209a6222015-10-16 09:51:07 +02001360 }
Michal Vasko209a6222015-10-16 09:51:07 +02001361
Michal Vasko89563fc2016-07-28 16:19:35 +02001362 for (j = 0; j < mod->deviation_size; ++j) {
1363 ptr = strstr(mod->deviation[j].target_name, cur_mod->name);
1364 if (ptr && ptr[strlen(cur_mod->name)] == ':') {
1365 cont = lyd_new(parent, NULL, "deviation");
1366 if (!cont) {
1367 return EXIT_FAILURE;
1368 }
1369
1370 if (!lyd_new_leaf(cont, NULL, "name", mod->name)) {
1371 return EXIT_FAILURE;
1372 }
1373 if (!lyd_new_leaf(cont, NULL, "revision", (mod->rev_size ? mod->rev[0].date : ""))) {
1374 return EXIT_FAILURE;
1375 }
Michal Vasko0c2215b2016-08-25 14:18:43 +02001376
1377 break;
Michal Vasko89563fc2016-07-28 16:19:35 +02001378 }
Michal Vasko209a6222015-10-16 09:51:07 +02001379 }
1380 }
1381 }
1382
1383 return EXIT_SUCCESS;
1384}
1385
1386static int
1387ylib_submodules(struct lyd_node *parent, struct lys_module *cur_mod)
1388{
1389 int i;
Radek Krejcia77904e2016-02-25 16:23:45 +01001390 char *str;
Radek Krejcid9723912016-09-16 17:06:06 +02001391 struct lyd_node *item;
Michal Vasko209a6222015-10-16 09:51:07 +02001392
Radek Krejcic071c542016-01-27 14:57:51 +01001393 for (i = 0; i < cur_mod->inc_size && cur_mod->inc[i].submodule; ++i) {
Radek Krejcid9723912016-09-16 17:06:06 +02001394 item = lyd_new(parent, NULL, "submodule");
Radek Krejci6e05cea2015-12-10 16:34:37 +01001395 if (!item) {
Michal Vasko209a6222015-10-16 09:51:07 +02001396 return EXIT_FAILURE;
1397 }
1398
Radek Krejci6e05cea2015-12-10 16:34:37 +01001399 if (!lyd_new_leaf(item, NULL, "name", cur_mod->inc[i].submodule->name)) {
Michal Vasko209a6222015-10-16 09:51:07 +02001400 return EXIT_FAILURE;
1401 }
Radek Krejci6e05cea2015-12-10 16:34:37 +01001402 if (!lyd_new_leaf(item, NULL, "revision", (cur_mod->inc[i].submodule->rev_size ?
Michal Vasko3e671b52015-10-23 16:23:15 +02001403 cur_mod->inc[i].submodule->rev[0].date : ""))) {
Michal Vasko209a6222015-10-16 09:51:07 +02001404 return EXIT_FAILURE;
1405 }
Radek Krejcia77904e2016-02-25 16:23:45 +01001406 if (cur_mod->inc[i].submodule->filepath) {
Radek Krejci95aa2012016-03-03 11:21:09 +01001407 if (asprintf(&str, "file://%s", cur_mod->inc[i].submodule->filepath) == -1) {
Radek Krejcia77904e2016-02-25 16:23:45 +01001408 LOGMEM;
1409 return EXIT_FAILURE;
Radek Krejci6e65af92016-03-07 12:48:19 +01001410 } else if (!lyd_new_leaf(item, NULL, "schema", str)) {
Radek Krejci19f9ede2016-02-25 16:29:21 +01001411 free(str);
Radek Krejcia77904e2016-02-25 16:23:45 +01001412 return EXIT_FAILURE;
1413 }
Radek Krejci19f9ede2016-02-25 16:29:21 +01001414 free(str);
Michal Vasko209a6222015-10-16 09:51:07 +02001415 }
1416 }
1417
1418 return EXIT_SUCCESS;
1419}
1420
1421API struct lyd_node *
1422ly_ctx_info(struct ly_ctx *ctx)
1423{
1424 int i;
1425 char id[8];
Radek Krejcia77904e2016-02-25 16:23:45 +01001426 char *str;
Michal Vasko1e62a092015-12-01 12:27:20 +01001427 const struct lys_module *mod;
Michal Vasko209a6222015-10-16 09:51:07 +02001428 struct lyd_node *root, *cont;
1429
Michal Vasko7eccc6c2016-03-24 14:56:33 +01001430 if (!ctx) {
1431 ly_errno = LY_EINVAL;
1432 return NULL;
1433 }
1434
Radek Krejcibd9e8d22016-02-03 14:11:48 +01001435 mod = ly_ctx_get_module(ctx, "ietf-yang-library", IETF_YANG_LIB_REV);
1436 if (!mod || !mod->data) {
1437 LOGINT;
Michal Vasko209a6222015-10-16 09:51:07 +02001438 return NULL;
1439 }
1440
Radek Krejcibd9e8d22016-02-03 14:11:48 +01001441 root = lyd_new(NULL, mod, "modules-state");
Michal Vasko209a6222015-10-16 09:51:07 +02001442 if (!root) {
1443 return NULL;
1444 }
1445
1446 for (i = 0; i < ctx->models.used; ++i) {
Radek Krejci0ec51da2016-12-14 16:42:03 +01001447 if (ctx->models.list[i]->disabled) {
1448 /* skip the disabled modules */
1449 continue;
1450 }
1451
Michal Vasko209a6222015-10-16 09:51:07 +02001452 cont = lyd_new(root, NULL, "module");
1453 if (!cont) {
1454 lyd_free(root);
1455 return NULL;
1456 }
1457
Michal Vasko3e671b52015-10-23 16:23:15 +02001458 if (!lyd_new_leaf(cont, NULL, "name", ctx->models.list[i]->name)) {
Michal Vasko209a6222015-10-16 09:51:07 +02001459 lyd_free(root);
1460 return NULL;
1461 }
Michal Vasko3e671b52015-10-23 16:23:15 +02001462 if (!lyd_new_leaf(cont, NULL, "revision", (ctx->models.list[i]->rev_size ?
Michal Vasko209a6222015-10-16 09:51:07 +02001463 ctx->models.list[i]->rev[0].date : ""))) {
1464 lyd_free(root);
1465 return NULL;
1466 }
Radek Krejcia77904e2016-02-25 16:23:45 +01001467 if (ctx->models.list[i]->filepath) {
Radek Krejci15412ca2016-03-03 11:16:52 +01001468 if (asprintf(&str, "file://%s", ctx->models.list[i]->filepath) == -1) {
Radek Krejcia77904e2016-02-25 16:23:45 +01001469 LOGMEM;
1470 lyd_free(root);
1471 return NULL;
1472 } else if (!lyd_new_leaf(cont, NULL, "schema", str)) {
Radek Krejci19f9ede2016-02-25 16:29:21 +01001473 free(str);
Radek Krejcia77904e2016-02-25 16:23:45 +01001474 lyd_free(root);
1475 return NULL;
1476 }
Radek Krejci19f9ede2016-02-25 16:29:21 +01001477 free(str);
Michal Vasko209a6222015-10-16 09:51:07 +02001478 }
Michal Vasko3e671b52015-10-23 16:23:15 +02001479 if (!lyd_new_leaf(cont, NULL, "namespace", ctx->models.list[i]->ns)) {
Michal Vasko209a6222015-10-16 09:51:07 +02001480 lyd_free(root);
1481 return NULL;
1482 }
1483 if (ylib_feature(cont, ctx->models.list[i])) {
1484 lyd_free(root);
1485 return NULL;
1486 }
Michal Vaskoff006c12016-02-17 11:15:19 +01001487 if (ylib_deviation(cont, ctx->models.list[i])) {
Michal Vasko209a6222015-10-16 09:51:07 +02001488 lyd_free(root);
1489 return NULL;
1490 }
1491 if (ctx->models.list[i]->implemented
Radek Krejcibd9e8d22016-02-03 14:11:48 +01001492 && !lyd_new_leaf(cont, NULL, "conformance-type", "implement")) {
Michal Vasko209a6222015-10-16 09:51:07 +02001493 lyd_free(root);
1494 return NULL;
1495 }
1496 if (!ctx->models.list[i]->implemented
Radek Krejcibd9e8d22016-02-03 14:11:48 +01001497 && !lyd_new_leaf(cont, NULL, "conformance-type", "import")) {
Michal Vasko209a6222015-10-16 09:51:07 +02001498 lyd_free(root);
1499 return NULL;
1500 }
1501 if (ylib_submodules(cont, ctx->models.list[i])) {
1502 lyd_free(root);
1503 return NULL;
1504 }
1505 }
1506
1507 sprintf(id, "%u", ctx->models.module_set_id);
Michal Vasko3e671b52015-10-23 16:23:15 +02001508 if (!lyd_new_leaf(root, mod, "module-set-id", id)) {
Michal Vasko209a6222015-10-16 09:51:07 +02001509 lyd_free(root);
1510 return NULL;
1511 }
1512
Michal Vaskocdb90172016-09-13 09:34:36 +02001513 if (lyd_validate(&root, LYD_OPT_NOSIBLINGS, NULL)) {
Michal Vasko209a6222015-10-16 09:51:07 +02001514 lyd_free(root);
1515 return NULL;
1516 }
1517
1518 return root;
1519}
Michal Vaskob3744402017-08-03 14:23:58 +02001520
1521API const struct lys_node *
1522ly_ctx_get_node(struct ly_ctx *ctx, const struct lys_node *start, const char *nodeid, int output)
1523{
1524 const struct lys_node *node;
1525
1526 if (!ctx || !nodeid || ((nodeid[0] != '/') && !start)) {
1527 ly_errno = LY_EINVAL;
1528 return NULL;
1529 }
1530
1531 /* sets error and everything */
1532 node = resolve_json_nodeid(nodeid, ctx, start, output);
1533
1534 return node;
1535}