blob: ec3ac208e839790dbc25bf6b1f3d6319d95bc01c [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 Krejcifd4e6e32015-08-10 15:00:51 +020016#include <stddef.h>
Radek Krejcida04f4a2015-05-21 12:54:09 +020017#include <stdlib.h>
18#include <string.h>
19#include <sys/types.h>
20#include <sys/stat.h>
21#include <unistd.h>
22#include <errno.h>
23#include <fcntl.h>
24
25#include "common.h"
26#include "context.h"
Radek Krejci41912fe2015-10-22 10:22:12 +020027#include "dict_private.h"
Michal Vasko209a6222015-10-16 09:51:07 +020028#include "parser.h"
Radek Krejcibc9cf932015-07-30 11:09:39 +020029#include "tree_internal.h"
Radek Krejci83a4bac2017-02-07 15:53:04 +010030#include "resolve.h"
Radek Krejcida04f4a2015-05-21 12:54:09 +020031
Radek Krejci858ad952017-01-04 11:16:32 +010032/*
33 * counter for references to the extensions plugins (for the number of contexts)
34 * located in extensions.c
35 */
36extern unsigned int ext_plugins_ref;
37
Radek Krejci532e5e92017-02-22 12:59:24 +010038#define IETF_YANG_METADATA_PATH "../models/ietf-yang-metadata@2016-08-05.h"
39#define YANG_PATH "../models/yang@2017-02-20.h"
Michal Vasko8d054e42015-08-03 12:42:06 +020040#define IETF_INET_TYPES_PATH "../models/ietf-inet-types@2013-07-15.h"
Michal Vasko21181c42015-08-03 13:46:45 +020041#define IETF_YANG_TYPES_PATH "../models/ietf-yang-types@2013-07-15.h"
Radek Krejcid9723912016-09-16 17:06:06 +020042#define IETF_YANG_LIB_PATH "../models/ietf-yang-library@2016-06-21.h"
43#define IETF_YANG_LIB_REV "2016-06-21"
Michal Vasko8d054e42015-08-03 12:42:06 +020044
Radek Krejci532e5e92017-02-22 12:59:24 +010045#include IETF_YANG_METADATA_PATH
46#include YANG_PATH
Michal Vasko8d054e42015-08-03 12:42:06 +020047#include IETF_INET_TYPES_PATH
Michal Vasko21181c42015-08-03 13:46:45 +020048#include IETF_YANG_TYPES_PATH
Michal Vasko8d054e42015-08-03 12:42:06 +020049#include IETF_YANG_LIB_PATH
50
Radek Krejci03203412016-06-23 15:20:53 +020051static struct internal_modules_s {
52 const char *name;
53 const char *revision;
54 const char *data;
55 uint8_t implemented;
56 LYS_INFORMAT format;
Michal Vasko2d051a12017-04-21 09:28:57 +020057} internal_modules[LY_INTERNAL_MODULE_COUNT] = {
Radek Krejci532e5e92017-02-22 12:59:24 +010058 {"ietf-yang-metadata", "2016-08-05", (const char*)ietf_yang_metadata_2016_08_05_yin, 0, LYS_IN_YIN},
59 {"yang", "2017-02-20", (const char*)yang_2017_02_20_yin, 1, LYS_IN_YIN},
Radek Krejci03203412016-06-23 15:20:53 +020060 {"ietf-inet-types", "2013-07-15", (const char*)ietf_inet_types_2013_07_15_yin, 0, LYS_IN_YIN},
61 {"ietf-yang-types", "2013-07-15", (const char*)ietf_yang_types_2013_07_15_yin, 0, LYS_IN_YIN},
Radek Krejcid9723912016-09-16 17:06:06 +020062 {"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 +020063};
64
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020065API struct ly_ctx *
66ly_ctx_new(const char *search_dir)
Radek Krejcida04f4a2015-05-21 12:54:09 +020067{
Radek Krejcia8d111f2017-05-31 13:57:37 +020068 struct ly_ctx *ctx = NULL;
Michal Vasko7d7de952016-05-02 17:13:14 +020069 struct lys_module *module;
Radek Krejcia8d111f2017-05-31 13:57:37 +020070 char *cwd = NULL;
Radek Krejci03203412016-06-23 15:20:53 +020071 int i;
Radek Krejcida04f4a2015-05-21 12:54:09 +020072
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020073 ctx = calloc(1, sizeof *ctx);
Radek Krejcia8d111f2017-05-31 13:57:37 +020074 LY_CHECK_ERR_RETURN(!ctx, LOGMEM, NULL);
Radek Krejcida04f4a2015-05-21 12:54:09 +020075
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020076 /* dictionary */
77 lydict_init(&ctx->dict);
Radek Krejcida04f4a2015-05-21 12:54:09 +020078
Radek Krejci858ad952017-01-04 11:16:32 +010079 /* plugins */
Radek Krejci858ad952017-01-04 11:16:32 +010080 lyext_load_plugins();
81
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020082 /* models list */
83 ctx->models.list = calloc(16, sizeof *ctx->models.list);
Radek Krejcia8d111f2017-05-31 13:57:37 +020084 LY_CHECK_ERR_RETURN(!ctx->models.list, LOGMEM; free(ctx), NULL);
Radek Krejci37d02632017-02-21 14:14:11 +010085 ext_plugins_ref++;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020086 ctx->models.used = 0;
87 ctx->models.size = 16;
88 if (search_dir) {
89 cwd = get_current_dir_name();
90 if (chdir(search_dir)) {
91 LOGERR(LY_ESYS, "Unable to use search directory \"%s\" (%s)",
92 search_dir, strerror(errno));
Radek Krejcia8d111f2017-05-31 13:57:37 +020093 goto error;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020094 }
Radek Krejcida9f8392017-03-25 19:40:56 -050095 ctx->models.search_paths = malloc(2 * sizeof *ctx->models.search_paths);
Radek Krejcia8d111f2017-05-31 13:57:37 +020096 LY_CHECK_ERR_GOTO(!ctx->models.search_paths, LOGMEM, error);
Radek Krejcida9f8392017-03-25 19:40:56 -050097 ctx->models.search_paths[0] = get_current_dir_name();
98 ctx->models.search_paths[1] = NULL;
Radek Krejci15412ca2016-03-03 11:16:52 +010099 if (chdir(cwd)) {
100 LOGWRN("Unable to return back to working directory \"%s\" (%s)",
101 cwd, strerror(errno));
102 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200103 }
Michal Vasko14719b22015-08-03 12:47:55 +0200104 ctx->models.module_set_id = 1;
105
Radek Krejci03203412016-06-23 15:20:53 +0200106 /* load internal modules */
Michal Vasko2d051a12017-04-21 09:28:57 +0200107 for (i = 0; i < LY_INTERNAL_MODULE_COUNT; i++) {
Radek Krejci03203412016-06-23 15:20:53 +0200108 module = (struct lys_module *)lys_parse_mem(ctx, internal_modules[i].data, internal_modules[i].format);
109 if (!module) {
Radek Krejcia8d111f2017-05-31 13:57:37 +0200110 goto error;
Radek Krejci03203412016-06-23 15:20:53 +0200111 }
112 module->implemented = internal_modules[i].implemented;
Michal Vasko8d054e42015-08-03 12:42:06 +0200113 }
Radek Krejcida04f4a2015-05-21 12:54:09 +0200114
Radek Krejcia8d111f2017-05-31 13:57:37 +0200115 /* cleanup */
116 free(cwd);
117
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200118 return ctx;
Radek Krejcia8d111f2017-05-31 13:57:37 +0200119
120error:
121 free(cwd);
122 ly_ctx_destroy(ctx, NULL);
123 return NULL;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200124}
125
Radek Krejci69333c92017-03-17 16:14:43 +0100126static struct ly_ctx *
127ly_ctx_new_yl_common(const char *search_dir, const char *input, LYD_FORMAT format,
128 struct lyd_node* (*parser_func)(struct ly_ctx*, const char*, LYD_FORMAT, int,...))
129{
130 unsigned int u;
131 struct lyd_node *module, *node;
132 const char *name, *revision;
Radek Krejci5cb217d2017-03-25 16:07:52 -0500133 struct ly_set features = {0, 0, {NULL}};
Radek Krejci69333c92017-03-17 16:14:43 +0100134 const struct lys_module *mod;
135 struct lyd_node *yltree = NULL;
136 struct ly_ctx *ctx = NULL;
137
138 /* create empty (with internal modules including ietf-yang-library) context */
139 ctx = ly_ctx_new(search_dir);
140 if (!ctx) {
141 goto error;
142 }
143
144 /* parse yang library data tree */
145 yltree = parser_func(ctx, input, format, LYD_OPT_DATA, NULL);
146 if (!yltree) {
147 goto error;
148 }
149
150 /* process the data tree */
151 LY_TREE_FOR(yltree->child, module) {
152 if (module->schema->nodetype == LYS_LEAF) {
153 /* module-set-id - ignore it */
154 continue;
155 }
156
157 /* initiate */
158 name = NULL;
159 revision = NULL;
160 ly_set_clean(&features);
161
162 LY_TREE_FOR(module->child, node) {
163 if (!strcmp(node->schema->name, "name")) {
164 name = ((struct lyd_node_leaf_list*)node)->value_str;
165 } else if (!strcmp(node->schema->name, "revision")) {
166 revision = ((struct lyd_node_leaf_list*)node)->value_str;
167 } else if (!strcmp(node->schema->name, "feature")) {
168 ly_set_add(&features, node, LY_SET_OPT_USEASLIST);
169 } else if (!strcmp(node->schema->name, "conformance-type") &&
170 ((struct lyd_node_leaf_list*)node)->value.enm->value) {
171 /* imported module - skip it, it will be loaded as a side effect
172 * of loading another module */
173 goto next_module;
174 }
175 }
176
177 /* use the gathered data to load the module */
178 mod = ly_ctx_load_module(ctx, name, revision);
179 if (!mod) {
180 LOGERR(LY_EINVAL, "Unable to load module specified by yang library data.");
181 goto error;
182 }
183
184 /* set features */
185 for (u = 0; u < features.number; u++) {
186 lys_features_enable(mod, ((struct lyd_node_leaf_list*)features.set.d[u])->value_str);
187 }
188
189next_module:;
190 }
191
192 if (0) {
193 /* skip context destroy in case of success */
194error:
195 ly_ctx_destroy(ctx, NULL);
196 ctx = NULL;
197 }
198
199 /* cleanup */
200 if (yltree) {
201 /* yang library data tree */
202 lyd_free_withsiblings(yltree);
203 }
204
205 return ctx;
206}
207
208API struct ly_ctx *
209ly_ctx_new_ylpath(const char *search_dir, const char *path, LYD_FORMAT format)
210{
211 return ly_ctx_new_yl_common(search_dir, path, format, lyd_parse_path);
212}
213
214API struct ly_ctx *
215ly_ctx_new_ylmem(const char *search_dir, const char *data, LYD_FORMAT format)
216{
217 return ly_ctx_new_yl_common(search_dir, data, format, lyd_parse_mem);
218}
219
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200220API void
Radek Krejci819dd4b2017-03-07 15:35:48 +0100221ly_ctx_set_allimplemented(struct ly_ctx *ctx)
222{
223 if (!ctx) {
224 return;
225 }
226
227 ctx->models.flags |= LY_CTX_ALLIMPLEMENTED;
228}
229
230API void
231ly_ctx_unset_allimplemented(struct ly_ctx *ctx)
232{
233 if (!ctx) {
234 return;
235 }
236
237 ctx->models.flags &= ~LY_CTX_ALLIMPLEMENTED;
238}
239
240API void
Michal Vasko60ba9a62015-07-03 14:42:31 +0200241ly_ctx_set_searchdir(struct ly_ctx *ctx, const char *search_dir)
242{
Radek Krejci426ea2b2017-06-13 12:41:51 +0200243 char *cwd = NULL, *new;
Radek Krejcida9f8392017-03-25 19:40:56 -0500244 int index = 0;
245 void *r;
Michal Vasko60ba9a62015-07-03 14:42:31 +0200246
247 if (!ctx) {
248 return;
249 }
250
251 if (search_dir) {
252 cwd = get_current_dir_name();
253 if (chdir(search_dir)) {
254 LOGERR(LY_ESYS, "Unable to use search directory \"%s\" (%s)",
255 search_dir, strerror(errno));
Radek Krejcia8d111f2017-05-31 13:57:37 +0200256 goto cleanup;
Michal Vasko60ba9a62015-07-03 14:42:31 +0200257 }
Radek Krejcida9f8392017-03-25 19:40:56 -0500258
Radek Krejci426ea2b2017-06-13 12:41:51 +0200259 new = get_current_dir_name();
Radek Krejcida9f8392017-03-25 19:40:56 -0500260 if (!ctx->models.search_paths) {
261 ctx->models.search_paths = malloc(2 * sizeof *ctx->models.search_paths);
Radek Krejcia8d111f2017-05-31 13:57:37 +0200262 LY_CHECK_ERR_GOTO(!ctx->models.search_paths, LOGMEM, cleanup);
Radek Krejcida9f8392017-03-25 19:40:56 -0500263 index = 0;
264 } else {
Radek Krejci426ea2b2017-06-13 12:41:51 +0200265 for (index = 0; ctx->models.search_paths[index]; index++) {
266 /* check for duplicities */
267 if (!strcmp(new, ctx->models.search_paths[index])) {
268 /* path is already present */
269 free(new);
270 goto success;
271 }
272 }
Radek Krejcida9f8392017-03-25 19:40:56 -0500273 r = realloc(ctx->models.search_paths, (index + 2) * sizeof *ctx->models.search_paths);
Radek Krejcia8d111f2017-05-31 13:57:37 +0200274 LY_CHECK_ERR_GOTO(!r, LOGMEM, cleanup);
Radek Krejcida9f8392017-03-25 19:40:56 -0500275 ctx->models.search_paths = r;
276 }
Radek Krejci426ea2b2017-06-13 12:41:51 +0200277 ctx->models.search_paths[index] = new;
Radek Krejcida9f8392017-03-25 19:40:56 -0500278 ctx->models.search_paths[index + 1] = NULL;
Michal Vasko3eff9322015-11-10 11:02:30 +0100279
Radek Krejci426ea2b2017-06-13 12:41:51 +0200280success:
Radek Krejci15412ca2016-03-03 11:16:52 +0100281 if (chdir(cwd)) {
282 LOGWRN("Unable to return back to working directory \"%s\" (%s)",
283 cwd, strerror(errno));
284 }
Michal Vasko60ba9a62015-07-03 14:42:31 +0200285 }
Radek Krejcia8d111f2017-05-31 13:57:37 +0200286
287cleanup:
288 free(cwd);
Michal Vasko60ba9a62015-07-03 14:42:31 +0200289}
290
Radek Krejci426ea2b2017-06-13 12:41:51 +0200291API const char * const *
292ly_ctx_get_searchdirs(const struct ly_ctx *ctx)
Radek Krejci5a797572015-10-21 15:45:45 +0200293{
Radek Krejciee554172016-12-14 10:29:06 +0100294 if (!ctx) {
295 ly_errno = LY_EINVAL;
296 return NULL;
297 }
Radek Krejci426ea2b2017-06-13 12:41:51 +0200298 return (const char * const *)ctx->models.search_paths;
Radek Krejcida9f8392017-03-25 19:40:56 -0500299}
300
301API void
Radek Krejcidb4e9ff2017-06-13 16:26:14 +0200302ly_ctx_unset_searchdirs(struct ly_ctx *ctx, int index)
Radek Krejcida9f8392017-03-25 19:40:56 -0500303{
304 int i;
305
306 if (!ctx->models.search_paths) {
307 return;
308 }
309
310 for (i = 0; ctx->models.search_paths[i]; i++) {
Radek Krejcidb4e9ff2017-06-13 16:26:14 +0200311 if (index < 0 || index == i) {
312 free(ctx->models.search_paths[i]);
313 ctx->models.search_paths[i] = NULL;
314 } else if (i > index) {
315 ctx->models.search_paths[i - 1] = ctx->models.search_paths[i];
316 ctx->models.search_paths[i] = NULL;
317 }
Radek Krejcida9f8392017-03-25 19:40:56 -0500318 }
Radek Krejcidb4e9ff2017-06-13 16:26:14 +0200319 if (index < 0 || !ctx->models.search_paths[0]) {
320 free(ctx->models.search_paths);
321 ctx->models.search_paths = NULL;
322 }
Radek Krejci5a797572015-10-21 15:45:45 +0200323}
324
Michal Vasko60ba9a62015-07-03 14:42:31 +0200325API void
Radek Krejcifa0b5e02016-02-04 13:57:03 +0100326ly_ctx_destroy(struct ly_ctx *ctx, void (*private_destructor)(const struct lys_node *node, void *priv))
Radek Krejcida04f4a2015-05-21 12:54:09 +0200327{
Radek Krejcida9f8392017-03-25 19:40:56 -0500328 int i;
329
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200330 if (!ctx) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200331 return;
332 }
Radek Krejcida04f4a2015-05-21 12:54:09 +0200333
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200334 /* models list */
Radek Krejcic436a232017-02-08 14:43:11 +0100335 for (; ctx->models.used > 0; ctx->models.used--) {
Radek Krejcifc8411a2017-02-03 10:26:05 +0100336 /* remove the applied deviations and augments */
Radek Krejcic436a232017-02-08 14:43:11 +0100337 lys_sub_module_remove_devs_augs(ctx->models.list[ctx->models.used - 1]);
Radek Krejcifc8411a2017-02-03 10:26:05 +0100338 /* remove the module */
Radek Krejcic436a232017-02-08 14:43:11 +0100339 lys_free(ctx->models.list[ctx->models.used - 1], private_destructor, 0);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200340 }
Radek Krejcida9f8392017-03-25 19:40:56 -0500341 if (ctx->models.search_paths) {
342 for(i = 0; ctx->models.search_paths[i]; i++) {
343 free(ctx->models.search_paths[i]);
344 }
345 free(ctx->models.search_paths);
346 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200347 free(ctx->models.list);
Radek Krejcida04f4a2015-05-21 12:54:09 +0200348
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200349 /* dictionary */
350 lydict_clean(&ctx->dict);
Radek Krejcida04f4a2015-05-21 12:54:09 +0200351
Radek Krejci858ad952017-01-04 11:16:32 +0100352 /* plugins - will be removed only if this is the last context */
353 ext_plugins_ref--;
354 lyext_clean_plugins();
355
Radek Krejci8b76a4a2016-10-26 10:02:32 +0200356 /* clean the error list */
Radek Krejci00a0e712016-10-26 10:24:46 +0200357 ly_err_clean(0);
Radek Krejci8b76a4a2016-10-26 10:02:32 +0200358
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200359 free(ctx);
Radek Krejcida04f4a2015-05-21 12:54:09 +0200360}
361
Michal Vasko1e62a092015-12-01 12:27:20 +0100362API const struct lys_submodule *
Radek Krejci62f0da72016-03-07 11:35:43 +0100363ly_ctx_get_submodule2(const struct lys_module *main_module, const char *submodule)
364{
Radek Krejcid4c1d0f2017-01-19 16:11:38 +0100365 const struct lys_submodule *result;
Radek Krejci62f0da72016-03-07 11:35:43 +0100366 int i;
367
368 if (!main_module || !submodule) {
369 ly_errno = LY_EINVAL;
370 return NULL;
371 }
372
373 /* search in submodules list */
374 for (i = 0; i < main_module->inc_size; i++) {
375 result = main_module->inc[i].submodule;
Radek Krejcid4c1d0f2017-01-19 16:11:38 +0100376 if (ly_strequal(submodule, result->name, 0)) {
Radek Krejci62f0da72016-03-07 11:35:43 +0100377 return result;
378 }
Radek Krejcid4c1d0f2017-01-19 16:11:38 +0100379
380 /* in YANG 1.1 all the submodules must be included in the main module, so we are done.
381 * YANG 1.0 allows (is unclear about denying it) to include a submodule only in another submodule
382 * but when libyang parses such a module it adds the include into the main module so we are also done.
383 */
Radek Krejci62f0da72016-03-07 11:35:43 +0100384 }
385
Radek Krejcid4c1d0f2017-01-19 16:11:38 +0100386
Radek Krejci62f0da72016-03-07 11:35:43 +0100387 return NULL;
388}
389
390API const struct lys_submodule *
Michal Vaskof6d94c62016-04-05 11:21:54 +0200391ly_ctx_get_submodule(const struct ly_ctx *ctx, const char *module, const char *revision, const char *submodule,
392 const char *sub_revision)
Radek Krejciefaeba32015-05-27 14:30:57 +0200393{
Radek Krejcie7973552016-03-07 08:12:01 +0100394 const struct lys_module *mainmod;
Michal Vaskof6d94c62016-04-05 11:21:54 +0200395 const struct lys_submodule *ret = NULL, *submod;
396 uint32_t idx = 0;
Radek Krejciefaeba32015-05-27 14:30:57 +0200397
Michal Vaskof6d94c62016-04-05 11:21:54 +0200398 if (!ctx || !submodule || (revision && !module)) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200399 ly_errno = LY_EINVAL;
400 return NULL;
401 }
Radek Krejciefaeba32015-05-27 14:30:57 +0200402
Michal Vaskof6d94c62016-04-05 11:21:54 +0200403 while ((mainmod = ly_ctx_get_module_iter(ctx, &idx))) {
404 if (module && strcmp(mainmod->name, module)) {
405 /* main module name does not match */
406 continue;
407 }
408
409 if (revision && (!mainmod->rev || strcmp(revision, mainmod->rev[0].date))) {
410 /* main module revision does not match */
411 continue;
412 }
413
414 submod = ly_ctx_get_submodule2(mainmod, submodule);
415 if (!submod) {
416 continue;
417 }
418
419 if (!sub_revision) {
420 /* store only if newer */
421 if (ret) {
422 if (submod->rev && (!ret->rev || (strcmp(submod->rev[0].date, ret->rev[0].date) > 0))) {
423 ret = submod;
424 }
425 } else {
426 ret = submod;
427 }
428 } else {
429 /* store only if revision matches, we are done if it does */
430 if (!submod->rev) {
431 continue;
432 } else if (!strcmp(sub_revision, submod->rev[0].date)) {
433 ret = submod;
434 break;
435 }
436 }
Radek Krejcia7533f22016-03-07 07:37:45 +0100437 }
Radek Krejcic071c542016-01-27 14:57:51 +0100438
Michal Vaskof6d94c62016-04-05 11:21:54 +0200439 return ret;
Radek Krejciefaeba32015-05-27 14:30:57 +0200440}
441
Michal Vasko1e62a092015-12-01 12:27:20 +0100442static const struct lys_module *
Radek Krejci0ec51da2016-12-14 16:42:03 +0100443ly_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 +0200444{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200445 int i;
Radek Krejcib8048692015-08-05 13:36:34 +0200446 struct lys_module *result = NULL;
Radek Krejciefaeba32015-05-27 14:30:57 +0200447
Radek Krejcifd4e6e32015-08-10 15:00:51 +0200448 if (!ctx || !key) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200449 ly_errno = LY_EINVAL;
450 return NULL;
451 }
Radek Krejciefaeba32015-05-27 14:30:57 +0200452
Radek Krejcidce51452015-06-16 15:20:08 +0200453 for (i = 0; i < ctx->models.used; i++) {
Radek Krejci0ec51da2016-12-14 16:42:03 +0100454 if (!with_disabled && ctx->models.list[i]->disabled) {
455 /* skip the disabled modules */
456 continue;
457 }
Radek Krejcifd4e6e32015-08-10 15:00:51 +0200458 /* use offset to get address of the pointer to string (char**), remember that offset is in
459 * bytes, so we have to cast the pointer to the module to (char*), finally, we want to have
460 * string not the pointer to string
461 */
462 if (!ctx->models.list[i] || strcmp(key, *(char**)(((char*)ctx->models.list[i]) + offset))) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200463 continue;
464 }
Radek Krejciefaeba32015-05-27 14:30:57 +0200465
Radek Krejcif647e612015-07-30 11:36:07 +0200466 if (!revision) {
467 /* compare revisons and remember the newest one */
468 if (result) {
469 if (!ctx->models.list[i]->rev_size) {
470 /* the current have no revision, keep the previous with some revision */
471 continue;
472 }
473 if (result->rev_size && strcmp(ctx->models.list[i]->rev[0].date, result->rev[0].date) < 0) {
474 /* the previous found matching module has a newer revision */
475 continue;
476 }
477 }
478
479 /* remember the current match and search for newer version */
480 result = ctx->models.list[i];
481 } else {
482 if (ctx->models.list[i]->rev_size && !strcmp(revision, ctx->models.list[i]->rev[0].date)) {
483 /* matching revision */
Michal Vasko97586502015-08-12 14:32:18 +0200484 result = ctx->models.list[i];
485 break;
Radek Krejcif647e612015-07-30 11:36:07 +0200486 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200487 }
488 }
Radek Krejciefaeba32015-05-27 14:30:57 +0200489
Radek Krejcif647e612015-07-30 11:36:07 +0200490 return result;
Radek Krejcifd4e6e32015-08-10 15:00:51 +0200491
492}
493
Michal Vasko1e62a092015-12-01 12:27:20 +0100494API const struct lys_module *
495ly_ctx_get_module_by_ns(const struct ly_ctx *ctx, const char *ns, const char *revision)
Radek Krejcifd4e6e32015-08-10 15:00:51 +0200496{
Radek Krejci0ec51da2016-12-14 16:42:03 +0100497 return ly_ctx_get_module_by(ctx, ns, offsetof(struct lys_module, ns), revision, 0);
Radek Krejcifd4e6e32015-08-10 15:00:51 +0200498}
499
Michal Vasko1e62a092015-12-01 12:27:20 +0100500API const struct lys_module *
501ly_ctx_get_module(const struct ly_ctx *ctx, const char *name, const char *revision)
Radek Krejcifd4e6e32015-08-10 15:00:51 +0200502{
Radek Krejci0ec51da2016-12-14 16:42:03 +0100503 return ly_ctx_get_module_by(ctx, name, offsetof(struct lys_module, name), revision, 0);
Radek Krejcida04f4a2015-05-21 12:54:09 +0200504}
Michal Vasko3ec07dc2015-06-30 15:51:30 +0200505
Radek Krejci21601a32016-03-07 11:39:27 +0100506API const struct lys_module *
507ly_ctx_get_module_older(const struct ly_ctx *ctx, const struct lys_module *module)
508{
509 int i;
510 const struct lys_module *result = NULL, *iter;
511
512 if (!ctx || !module || !module->rev_size) {
513 ly_errno = LY_EINVAL;
514 return NULL;
515 }
516
517
518 for (i = 0; i < ctx->models.used; i++) {
519 iter = ctx->models.list[i];
Radek Krejci0ec51da2016-12-14 16:42:03 +0100520 if (iter->disabled) {
521 /* skip the disabled modules */
522 continue;
523 }
Radek Krejci21601a32016-03-07 11:39:27 +0100524 if (iter == module || !iter->rev_size) {
525 /* iter is the module itself or iter has no revision */
526 continue;
527 }
528 if (!ly_strequal(module->name, iter->name, 0)) {
529 /* different module */
530 continue;
531 }
532 if (strcmp(iter->rev[0].date, module->rev[0].date) < 0) {
533 /* iter is older than module */
534 if (result) {
535 if (strcmp(iter->rev[0].date, result->rev[0].date) > 0) {
536 /* iter is newer than current result */
537 result = iter;
538 }
539 } else {
540 result = iter;
541 }
542 }
543 }
544
545 return result;
546}
547
Michal Vasko99b0aad2015-12-01 12:28:51 +0100548API void
Michal Vaskoca28aab2017-01-13 13:50:12 +0100549ly_ctx_set_module_imp_clb(struct ly_ctx *ctx, ly_module_imp_clb clb, void *user_data)
Michal Vasko82465962015-11-10 11:03:11 +0100550{
Michal Vaskoad9f92a2017-04-06 09:49:07 +0200551 if (!ctx) {
552 ly_errno = LY_EINVAL;
553 return;
554 }
555
Michal Vaskof53187d2017-01-13 13:23:14 +0100556 ctx->imp_clb = clb;
557 ctx->imp_clb_data = user_data;
Michal Vasko99b0aad2015-12-01 12:28:51 +0100558}
559
Michal Vaskof53187d2017-01-13 13:23:14 +0100560API ly_module_imp_clb
Michal Vaskoca28aab2017-01-13 13:50:12 +0100561ly_ctx_get_module_imp_clb(const struct ly_ctx *ctx, void **user_data)
Michal Vasko99b0aad2015-12-01 12:28:51 +0100562{
Radek Krejciee554172016-12-14 10:29:06 +0100563 if (!ctx) {
564 ly_errno = LY_EINVAL;
565 return NULL;
566 }
567
Michal Vasko99b0aad2015-12-01 12:28:51 +0100568 if (user_data) {
Michal Vaskof53187d2017-01-13 13:23:14 +0100569 *user_data = ctx->imp_clb_data;
Michal Vasko99b0aad2015-12-01 12:28:51 +0100570 }
Michal Vaskof53187d2017-01-13 13:23:14 +0100571 return ctx->imp_clb;
572}
573
574API void
Michal Vaskoca28aab2017-01-13 13:50:12 +0100575ly_ctx_set_module_data_clb(struct ly_ctx *ctx, ly_module_data_clb clb, void *user_data)
Michal Vaskof53187d2017-01-13 13:23:14 +0100576{
Michal Vaskoad9f92a2017-04-06 09:49:07 +0200577 if (!ctx) {
578 ly_errno = LY_EINVAL;
579 return;
580 }
581
Michal Vaskof53187d2017-01-13 13:23:14 +0100582 ctx->data_clb = clb;
583 ctx->data_clb_data = user_data;
584}
585
586API ly_module_data_clb
Michal Vaskoca28aab2017-01-13 13:50:12 +0100587ly_ctx_get_module_data_clb(const struct ly_ctx *ctx, void **user_data)
Michal Vaskof53187d2017-01-13 13:23:14 +0100588{
Michal Vaskoad9f92a2017-04-06 09:49:07 +0200589 if (!ctx) {
590 ly_errno = LY_EINVAL;
591 return NULL;
592 }
593
Michal Vaskof53187d2017-01-13 13:23:14 +0100594 if (user_data) {
595 *user_data = ctx->data_clb_data;
596 }
597 return ctx->data_clb;
Michal Vasko99b0aad2015-12-01 12:28:51 +0100598}
599
Radek Krejcibf4e4652016-10-21 15:44:13 +0200600const struct lys_module *
Michal Vasko84475152016-07-25 16:16:25 +0200601ly_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 +0200602 int implement, struct unres_schema *unres)
Michal Vasko99b0aad2015-12-01 12:28:51 +0100603{
Radek Krejcibf4e4652016-10-21 15:44:13 +0200604 const struct lys_module *mod;
Michal Vasko99b0aad2015-12-01 12:28:51 +0100605 char *module_data;
Radek Krejci03203412016-06-23 15:20:53 +0200606 int i;
Michal Vaskod3e975b2016-03-03 15:40:21 +0100607 void (*module_data_free)(void *module_data) = NULL;
Michal Vasko99b0aad2015-12-01 12:28:51 +0100608 LYS_INFORMAT format = LYS_IN_UNKNOWN;
Michal Vasko82465962015-11-10 11:03:11 +0100609
Michal Vasko84475152016-07-25 16:16:25 +0200610 if (!module) {
Radek Krejcibf4e4652016-10-21 15:44:13 +0200611 /* exception for internal modules */
Michal Vasko2d051a12017-04-21 09:28:57 +0200612 for (i = 0; i < LY_INTERNAL_MODULE_COUNT; i++) {
Michal Vasko84475152016-07-25 16:16:25 +0200613 if (ly_strequal(name, internal_modules[i].name, 0)) {
614 if (!revision || ly_strequal(revision, internal_modules[i].revision, 0)) {
615 /* return internal module */
616 return (struct lys_module *)ly_ctx_get_module(ctx, name, revision);
617 }
Radek Krejci03203412016-06-23 15:20:53 +0200618 }
619 }
Radek Krejcibf4e4652016-10-21 15:44:13 +0200620 if (revision) {
Radek Krejci0ec51da2016-12-14 16:42:03 +0100621 /* try to get the schema with the specific revision from the context,
622 * include the disabled modules in the search to avoid their duplication,
623 * they are enabled by the subsequent call to lys_set_implemented() */
Michal Vasko2d051a12017-04-21 09:28:57 +0200624 for (i = LY_INTERNAL_MODULE_COUNT, mod = NULL; i < ctx->models.used; i++) {
Radek Krejci0ec51da2016-12-14 16:42:03 +0100625 mod = ctx->models.list[i]; /* shortcut */
626 if (ly_strequal(name, mod->name, 0) && mod->rev_size && !strcmp(revision, mod->rev[0].date)) {
627 break;
628 }
629 mod = NULL;
630 }
Radek Krejcibf4e4652016-10-21 15:44:13 +0200631 if (mod) {
632 /* we get such a module, make it implemented */
633 if (lys_set_implemented(mod)) {
634 /* the schema cannot be implemented */
635 mod = NULL;
636 }
637 return mod;
638 }
639 }
Radek Krejci03203412016-06-23 15:20:53 +0200640 }
641
Michal Vaskof53187d2017-01-13 13:23:14 +0100642 if (ctx->imp_clb) {
Michal Vasko84475152016-07-25 16:16:25 +0200643 if (module) {
644 mod = lys_main_module(module);
Michal Vaskof53187d2017-01-13 13:23:14 +0100645 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 +0200646 } else {
Michal Vaskof53187d2017-01-13 13:23:14 +0100647 module_data = ctx->imp_clb(name, revision, NULL, NULL, ctx->imp_clb_data, &format, &module_data_free);
Michal Vasko84475152016-07-25 16:16:25 +0200648 }
Michal Vasko99b0aad2015-12-01 12:28:51 +0100649 if (!module_data) {
Radek Krejcibf4e4652016-10-21 15:44:13 +0200650 if (module || revision) {
651 /* we already know that the specified revision is not present in context, and we have no other
652 * option in case of submodules */
653 LOGERR(LY_ESYS, "User module retrieval callback failed!");
654 return NULL;
655 } else {
656 /* get the newest revision from the context */
Radek Krejci0ec51da2016-12-14 16:42:03 +0100657 mod = ly_ctx_get_module_by(ctx, name, offsetof(struct lys_module, name), revision, 1);
658 if (mod && mod->disabled) {
659 /* enable the required module */
660 lys_set_enabled(mod);
661 }
662 return mod;
Radek Krejcibf4e4652016-10-21 15:44:13 +0200663 }
Michal Vasko82465962015-11-10 11:03:11 +0100664 }
Michal Vasko84475152016-07-25 16:16:25 +0200665
666 if (module) {
Michal Vasko5b998712017-01-26 10:34:06 +0100667 mod = (struct lys_module *)lys_sub_parse_mem(module, module_data, format, unres);
Michal Vasko84475152016-07-25 16:16:25 +0200668 } else {
Michal Vasko29245662017-04-18 15:56:31 +0200669 mod = (struct lys_module *)lys_parse_mem_(ctx, module_data, format, 0, implement);
Michal Vasko84475152016-07-25 16:16:25 +0200670 }
671
Michal Vasko99b0aad2015-12-01 12:28:51 +0100672 if (module_data_free) {
673 module_data_free(module_data);
Michal Vasko82465962015-11-10 11:03:11 +0100674 }
Michal Vasko99b0aad2015-12-01 12:28:51 +0100675 } else {
Michal Vasko58e5f3e2016-07-28 11:06:34 +0200676 mod = lyp_search_file(ctx, module, name, revision, implement, unres);
Michal Vasko82465962015-11-10 11:03:11 +0100677 }
678
Michal Vasko84475152016-07-25 16:16:25 +0200679 return mod;
680}
681
682API const struct lys_module *
683ly_ctx_load_module(struct ly_ctx *ctx, const char *name, const char *revision)
684{
685 if (!ctx || !name) {
686 ly_errno = LY_EINVAL;
687 return NULL;
688 }
689
Radek Krejci05f15982017-06-13 15:26:10 +0200690 return ly_ctx_load_sub_module(ctx, NULL, name, revision && revision[0] ? revision : NULL, 1, NULL);
Michal Vasko82465962015-11-10 11:03:11 +0100691}
692
Radek Krejci85a54be2016-10-20 12:39:56 +0200693/*
694 * mods - set of removed modules, if NULL all modules are supposed to be removed so any backlink is invalid
695 */
Michal Vasko4be5fa22017-02-07 10:12:32 +0100696static void
697ctx_modules_undo_backlinks(struct ly_ctx *ctx, struct ly_set *mods)
Radek Krejci85a54be2016-10-20 12:39:56 +0200698{
699 int o;
700 uint8_t j;
701 unsigned int u, v;
702 struct lys_module *mod;
703 struct lys_node *elem, *next;
704 struct lys_node_leaf *leaf;
705
706 /* maintain backlinks (start with internal ietf-yang-library which have leafs as possible targets of leafrefs */
Michal Vasko2d051a12017-04-21 09:28:57 +0200707 for (o = LY_INTERNAL_MODULE_COUNT - 1; o < ctx->models.used; o++) {
Radek Krejci85a54be2016-10-20 12:39:56 +0200708 mod = ctx->models.list[o]; /* shortcut */
709
710 /* 1) features */
711 for (j = 0; j < mod->features_size; j++) {
712 if (!mod->features[j].depfeatures) {
713 continue;
714 }
715 for (v = 0; v < mod->features[j].depfeatures->number; v++) {
716 if (!mods || ly_set_contains(mods, ((struct lys_feature *)mod->features[j].depfeatures->set.g[v])->module) != -1) {
717 /* depending feature is in module to remove */
718 ly_set_rm_index(mod->features[j].depfeatures, v);
719 v--;
720 }
721 }
722 if (!mod->features[j].depfeatures->number) {
723 /* all backlinks removed */
724 ly_set_free(mod->features[j].depfeatures);
725 mod->features[j].depfeatures = NULL;
726 }
727 }
Michal Vasko4be5fa22017-02-07 10:12:32 +0100728
729 /* 2) identities */
Radek Krejci85a54be2016-10-20 12:39:56 +0200730 for (u = 0; u < mod->ident_size; u++) {
731 if (!mod->ident[u].der) {
732 continue;
733 }
734 for (v = 0; v < mod->ident[u].der->number; v++) {
735 if (!mods || ly_set_contains(mods, ((struct lys_ident *)mod->ident[u].der->set.g[v])->module) != -1) {
736 /* derived identity is in module to remove */
737 ly_set_rm_index(mod->ident[u].der, v);
738 v--;
739 }
740 }
741 if (!mod->ident[u].der->number) {
742 /* all backlinks removed */
743 ly_set_free(mod->ident[u].der);
744 mod->ident[u].der = NULL;
745 }
746 }
747
Michal Vasko4be5fa22017-02-07 10:12:32 +0100748 /* 3) leafrefs */
Radek Krejci85a54be2016-10-20 12:39:56 +0200749 for (elem = next = mod->data; elem; elem = next) {
750 if (elem->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
751 leaf = (struct lys_node_leaf *)elem; /* shortcut */
752 if (leaf->backlinks) {
753 if (!mods) {
754 /* remove all backlinks */
755 ly_set_free(leaf->backlinks);
756 leaf->backlinks = NULL;
757 } else {
758 for (v = 0; v < leaf->backlinks->number; v++) {
759 if (ly_set_contains(mods, leaf->backlinks->set.s[v]->module) != -1) {
760 /* derived identity is in module to remove */
761 ly_set_rm_index(leaf->backlinks, v);
762 v--;
763 }
764 }
765 if (!leaf->backlinks->number) {
766 /* all backlinks removed */
767 ly_set_free(leaf->backlinks);
768 leaf->backlinks = NULL;
769 }
770 }
771 }
772 }
773
774 /* select next element to process */
775 next = elem->child;
776 /* child exception for leafs, leaflists, anyxml and groupings */
777 if (elem->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA | LYS_GROUPING)) {
778 next = NULL;
779 }
780 if (!next) {
781 /* no children, try siblings */
782 next = elem->next;
783 }
784 while (!next) {
785 /* parent is already processed, go to its sibling */
786 elem = lys_parent(elem);
787 if (!elem) {
788 /* we are done, no next element to process */
789 break;
790 }
791 /* no siblings, go back through parents */
792 next = elem->next;
793 }
794 }
795 }
Michal Vasko4be5fa22017-02-07 10:12:32 +0100796}
Radek Krejci85a54be2016-10-20 12:39:56 +0200797
Michal Vasko4be5fa22017-02-07 10:12:32 +0100798static int
Radek Krejci83a4bac2017-02-07 15:53:04 +0100799ctx_modules_redo_backlinks(struct ly_set *mods)
Michal Vasko4be5fa22017-02-07 10:12:32 +0100800{
Radek Krejci83a4bac2017-02-07 15:53:04 +0100801 unsigned int i, j, k, s;
802 struct lys_module *mod;
803 struct lys_node *next, *elem;
804 struct lys_type *type;
805 struct lys_feature *feat;
Michal Vasko4be5fa22017-02-07 10:12:32 +0100806
Michal Vasko4be5fa22017-02-07 10:12:32 +0100807 for (i = 0; i < mods->number; ++i) {
Radek Krejci83a4bac2017-02-07 15:53:04 +0100808 mod = (struct lys_module *)mods->set.g[i]; /* shortcut */
Michal Vasko4be5fa22017-02-07 10:12:32 +0100809
Radek Krejci83a4bac2017-02-07 15:53:04 +0100810 /* identities */
Radek Krejci9e6af732017-04-27 14:40:25 +0200811 if (mod->implemented) {
812 for (j = 0; j < mod->ident_size; j++) {
813 for (k = 0; k < mod->ident[j].base_size; k++) {
814 resolve_identity_backlink_update(&mod->ident[j], mod->ident[j].base[k]);
815 }
Radek Krejci83a4bac2017-02-07 15:53:04 +0100816 }
817 }
Michal Vasko4be5fa22017-02-07 10:12:32 +0100818
Radek Krejci83a4bac2017-02-07 15:53:04 +0100819 /* features */
820 for (j = 0; j < mod->features_size; j++) {
821 for (k = 0; k < mod->features[j].iffeature_size; k++) {
822 resolve_iffeature_getsizes(&mod->features[j].iffeature[k], NULL, &s);
823 while (s--) {
824 feat = mod->features[j].iffeature[k].features[s]; /* shortcut */
825 if (!feat->depfeatures) {
826 feat->depfeatures = ly_set_new();
827 }
828 ly_set_add(feat->depfeatures, &mod->features[j], LY_SET_OPT_USEASLIST);
829 }
830 }
831 }
832
833 /* leafrefs */
834 LY_TREE_DFS_BEGIN(mod->data, next, elem) {
Michal Vaskofa3d2f72017-04-10 13:30:44 +0200835 if (elem->nodetype == LYS_GROUPING) {
836 goto next_sibling;
837 }
838
Radek Krejci83a4bac2017-02-07 15:53:04 +0100839 if (elem->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
840 type = &((struct lys_node_leaf *)elem)->type; /* shortcut */
841 if (type->base == LY_TYPE_LEAFREF) {
842 lys_leaf_add_leafref_target(type->info.lref.target, elem);
843 }
844 }
845
Michal Vaskofa3d2f72017-04-10 13:30:44 +0200846 /* select element for the next run - children first */
847 next = elem->child;
848
849 /* child exception for leafs, leaflists and anyxml without children */
850 if (elem->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
851 next = NULL;
852 }
853 if (!next) {
854next_sibling:
855 /* no children */
856 if (elem == mod->data) {
857 /* we are done, (START) has no children */
858 break;
859 }
860 /* try siblings */
861 next = elem->next;
862 }
863 while (!next) {
864 /* parent is already processed, go to its sibling */
865 elem = lys_parent(elem);
866
867 /* no siblings, go back through parents */
868 if (lys_parent(elem) == lys_parent(mod->data)) {
869 /* we are done, no next element to process */
870 break;
871 }
872 next = elem->next;
873 }
Radek Krejci83a4bac2017-02-07 15:53:04 +0100874 }
Michal Vasko4be5fa22017-02-07 10:12:32 +0100875 }
876
877 return 0;
Radek Krejci85a54be2016-10-20 12:39:56 +0200878}
879
Radek Krejci8c107fe2016-10-17 16:00:18 +0200880API int
Radek Krejci0ec51da2016-12-14 16:42:03 +0100881lys_set_disabled(const struct lys_module *module)
882{
883 struct ly_ctx *ctx; /* shortcut */
884 struct lys_module *mod;
885 struct ly_set *mods;
886 uint8_t j, imported;
887 int i, o;
Radek Krejci29eac3d2017-06-01 16:50:02 +0200888 unsigned int u, v;
Radek Krejci0ec51da2016-12-14 16:42:03 +0100889
890 if (!module) {
891 ly_errno = LY_EINVAL;
892 return EXIT_FAILURE;
893 } else if (module->disabled) {
894 /* already disabled module */
895 return EXIT_SUCCESS;
896 }
897 mod = (struct lys_module *)module;
898 ctx = mod->ctx;
899
900 /* avoid disabling internal modules */
Michal Vasko2d051a12017-04-21 09:28:57 +0200901 for (i = 0; i < LY_INTERNAL_MODULE_COUNT; i++) {
Radek Krejci0ec51da2016-12-14 16:42:03 +0100902 if (mod == ctx->models.list[i]) {
Michal Vasko2d051a12017-04-21 09:28:57 +0200903 LOGERR(LY_EINVAL, "Internal module \"%s\" cannot be disabled.", mod->name);
Radek Krejci0ec51da2016-12-14 16:42:03 +0100904 return EXIT_FAILURE;
905 }
906 }
907
908 /* disable the module */
909 mod->disabled = 1;
910
911 /* get the complete list of modules to disable because of dependencies,
912 * we are going also to disable all the imported (not implemented) modules
913 * that are not used in any other module */
914 mods = ly_set_new();
915 ly_set_add(mods, mod, 0);
916checkdependency:
Michal Vasko2d051a12017-04-21 09:28:57 +0200917 for (i = LY_INTERNAL_MODULE_COUNT; i < ctx->models.used; i++) {
Radek Krejci0ec51da2016-12-14 16:42:03 +0100918 mod = ctx->models.list[i]; /* shortcut */
919 if (mod->disabled) {
920 /* skip the already disabled modules */
921 continue;
922 }
923
924 /* check depndency of imported modules */
925 for (j = 0; j < mod->imp_size; j++) {
926 for (u = 0; u < mods->number; u++) {
927 if (mod->imp[j].module == mods->set.g[u]) {
928 /* module is importing some module to disable, so it must be also disabled */
929 mod->disabled = 1;
930 ly_set_add(mods, mod, 0);
931 /* we have to start again because some of the already checked modules can
932 * depend on the one we have just decided to disable */
933 goto checkdependency;
934 }
935 }
936 }
937 /* check if the imported module is used in any module supposed to be kept */
938 if (!mod->implemented) {
939 imported = 0;
Michal Vasko2d051a12017-04-21 09:28:57 +0200940 for (o = LY_INTERNAL_MODULE_COUNT; o < ctx->models.used; o++) {
Radek Krejci0ec51da2016-12-14 16:42:03 +0100941 if (ctx->models.list[o]->disabled) {
942 /* skip modules already disabled */
943 continue;
944 }
945 for (j = 0; j < ctx->models.list[o]->imp_size; j++) {
946 if (ctx->models.list[o]->imp[j].module == mod) {
947 /* the module is used in some other module not yet selected to be disabled */
948 imported = 1;
949 goto imported;
950 }
951 }
952 }
953imported:
954 if (!imported) {
955 /* module is not implemented and neither imported by any other module in context
956 * which is supposed to be kept enabled after this operation, so we are going to disable also
957 * this module */
958 mod->disabled = 1;
959 ly_set_add(mods, mod, 0);
960 /* we have to start again, this time not because other module can depend on this one
961 * (we know that there is no such module), but because the module can import module
962 * that could became useless. If there are no imports, we can continue */
963 if (mod->imp_size) {
964 goto checkdependency;
965 }
966 }
967 }
968 }
969
970 /* before removing applied deviations, augments and updating leafrefs, we have to enable the modules
971 * to disable to allow all that operations */
972 for (u = 0; u < mods->number; u++) {
973 ((struct lys_module *)mods->set.g[u])->disabled = 0;
974 }
975
976 /* maintain backlinks (start with internal ietf-yang-library which have leafs as possible targets of leafrefs */
Michal Vasko4be5fa22017-02-07 10:12:32 +0100977 ctx_modules_undo_backlinks(ctx, mods);
Radek Krejci0ec51da2016-12-14 16:42:03 +0100978
979 /* remove the applied deviations and augments */
980 for (u = 0; u < mods->number; u++) {
981 lys_sub_module_remove_devs_augs((struct lys_module *)mods->set.g[u]);
982 }
983
Radek Krejci29eac3d2017-06-01 16:50:02 +0200984 /* now again disable the modules to disable and disable also all its submodules */
Radek Krejci0ec51da2016-12-14 16:42:03 +0100985 for (u = 0; u < mods->number; u++) {
Radek Krejci29eac3d2017-06-01 16:50:02 +0200986 mod = (struct lys_module *)mods->set.g[u];
987 mod->disabled = 1;
988 for (v = 0; v < mod->inc_size; v++) {
989 mod->inc[v].submodule->disabled = 1;
990 }
Radek Krejci0ec51da2016-12-14 16:42:03 +0100991 }
992
993 /* free the set */
994 ly_set_free(mods);
995
996 /* update the module-set-id */
997 ctx->models.module_set_id++;
998
999 return EXIT_SUCCESS;
1000}
1001
1002static void
1003lys_set_enabled_(struct ly_set *mods, struct lys_module *mod)
1004{
1005 unsigned int i;
1006
1007 ly_set_add(mods, mod, 0);
1008 mod->disabled = 0;
1009
Radek Krejci29eac3d2017-06-01 16:50:02 +02001010 for (i = 0; i < mod->inc_size; i++) {
1011 mod->inc[i].submodule->disabled = 0;
1012 }
1013
Radek Krejci0ec51da2016-12-14 16:42:03 +01001014 /* go recursively */
1015 for (i = 0; i < mod->imp_size; i++) {
1016 if (!mod->imp[i].module->disabled) {
1017 continue;
1018 }
1019
1020 lys_set_enabled_(mods, mod->imp[i].module);
1021 }
1022}
1023
1024API int
1025lys_set_enabled(const struct lys_module *module)
1026{
1027 struct ly_ctx *ctx; /* shortcut */
1028 struct lys_module *mod;
1029 struct ly_set *mods, *disabled;
1030 int i;
Radek Krejci29eac3d2017-06-01 16:50:02 +02001031 unsigned int u, v, w;
Radek Krejci0ec51da2016-12-14 16:42:03 +01001032
1033 if (!module) {
1034 ly_errno = LY_EINVAL;
1035 return EXIT_FAILURE;
1036 } else if (!module->disabled) {
1037 /* already enabled module */
1038 return EXIT_SUCCESS;
1039 }
1040 mod = (struct lys_module *)module;
1041 ctx = mod->ctx;
1042
1043 /* avoid disabling internal modules */
Michal Vasko2d051a12017-04-21 09:28:57 +02001044 for (i = 0; i < LY_INTERNAL_MODULE_COUNT; i++) {
Radek Krejci0ec51da2016-12-14 16:42:03 +01001045 if (mod == ctx->models.list[i]) {
1046 LOGERR(LY_EINVAL, "Internal module \"%s\" cannot be removed.", mod->name);
1047 return EXIT_FAILURE;
1048 }
1049 }
1050
1051 mods = ly_set_new();
1052 disabled = ly_set_new();
1053
1054 /* enable the module, including its dependencies */
1055 lys_set_enabled_(mods, mod);
1056
1057 /* we will go through the all disabled modules in the context, if the module has no dependency (import)
1058 * that is still disabled AND at least one of its imported module is from the set we are enabling now,
1059 * it is going to be also enabled. This way we try to revert everething that was possibly done by
1060 * lys_set_disabled(). */
1061checkdependency:
Michal Vasko2d051a12017-04-21 09:28:57 +02001062 for (i = LY_INTERNAL_MODULE_COUNT; i < ctx->models.used; i++) {
Radek Krejci0ec51da2016-12-14 16:42:03 +01001063 mod = ctx->models.list[i]; /* shortcut */
1064 if (!mod->disabled || ly_set_contains(disabled, mod) != -1) {
1065 /* skip the enabled modules */
1066 continue;
1067 }
1068
1069 /* check imported modules */
1070 for (u = 0; u < mod->imp_size; u++) {
1071 if (mod->imp[u].module->disabled) {
1072 /* it has disabled dependency so it must stay disabled */
1073 break;
1074 }
1075 }
1076 if (u < mod->imp_size) {
1077 /* it has disabled dependency, continue with the next module in the context */
1078 continue;
1079 }
1080
1081 /* get know if at least one of the imported modules is being enabled this time */
1082 for (u = 0; u < mod->imp_size; u++) {
1083 for (v = 0; v < mods->number; v++) {
1084 if (mod->imp[u].module == mods->set.g[v]) {
1085 /* yes, it is, so they are connected and we are going to enable it as well,
1086 * it is not necessary to call recursive lys_set_enable_() because we already
1087 * know that there is no disabled import to enable */
1088 mod->disabled = 0;
1089 ly_set_add(mods, mod, 0);
Radek Krejci29eac3d2017-06-01 16:50:02 +02001090 for (w = 0; w < mod->inc_size; w++) {
1091 mod->inc[w].submodule->disabled = 0;
1092 }
Radek Krejci0ec51da2016-12-14 16:42:03 +01001093 /* we have to start again because some of the already checked modules can
1094 * depend on the one we have just decided to enable */
1095 goto checkdependency;
1096 }
1097 }
1098 }
1099
1100 /* this module is disabled, but it does not depend on any other disabled module and none
1101 * of its imports was not enabled in this call. No future enabling of the disabled module
1102 * will change this so we can remember the module and skip it next time we will have to go
1103 * through the all context because of the checkdependency goto.
1104 */
1105 ly_set_add(disabled, mod, 0);
1106 }
1107
1108 /* maintain backlinks (start with internal ietf-yang-library which have leafs as possible targets of leafrefs */
Radek Krejci83a4bac2017-02-07 15:53:04 +01001109 ctx_modules_redo_backlinks(mods);
Radek Krejci0ec51da2016-12-14 16:42:03 +01001110
1111 /* re-apply the deviations and augments */
1112 for (v = 0; v < mods->number; v++) {
1113 lys_sub_module_apply_devs_augs((struct lys_module *)mods->set.g[v]);
1114 }
1115
1116 /* free the sets */
1117 ly_set_free(mods);
1118 ly_set_free(disabled);
1119
1120 /* update the module-set-id */
1121 ctx->models.module_set_id++;
1122
1123 return EXIT_SUCCESS;
1124}
1125
1126API int
1127ly_ctx_remove_module(const struct lys_module *module,
Radek Krejci8c107fe2016-10-17 16:00:18 +02001128 void (*private_destructor)(const struct lys_node *node, void *priv))
1129{
Radek Krejci0ec51da2016-12-14 16:42:03 +01001130 struct ly_ctx *ctx; /* shortcut */
Radek Krejci8c107fe2016-10-17 16:00:18 +02001131 struct lys_module *mod = NULL;
1132 struct ly_set *mods;
1133 uint8_t j, imported;
1134 int i, o;
1135 unsigned int u;
1136
Radek Krejci0ec51da2016-12-14 16:42:03 +01001137 if (!module) {
Radek Krejci8c107fe2016-10-17 16:00:18 +02001138 ly_errno = LY_EINVAL;
1139 return EXIT_FAILURE;
1140 }
1141
Radek Krejci0ec51da2016-12-14 16:42:03 +01001142 mod = (struct lys_module *)module;
1143 ctx = mod->ctx;
1144
Radek Krejci8c107fe2016-10-17 16:00:18 +02001145 /* avoid removing internal modules ... */
Michal Vasko2d051a12017-04-21 09:28:57 +02001146 for (i = 0; i < LY_INTERNAL_MODULE_COUNT; i++) {
Radek Krejci8c107fe2016-10-17 16:00:18 +02001147 if (mod == ctx->models.list[i]) {
Radek Krejci0ec51da2016-12-14 16:42:03 +01001148 LOGERR(LY_EINVAL, "Internal module \"%s\" cannot be removed.", mod->name);
Radek Krejci8c107fe2016-10-17 16:00:18 +02001149 return EXIT_FAILURE;
1150 }
1151 }
1152 /* ... and hide the module from the further processing of the context modules list */
Michal Vasko2d051a12017-04-21 09:28:57 +02001153 for (i = LY_INTERNAL_MODULE_COUNT; i < ctx->models.used; i++) {
Radek Krejci8c107fe2016-10-17 16:00:18 +02001154 if (mod == ctx->models.list[i]) {
1155 ctx->models.list[i] = NULL;
1156 break;
1157 }
1158 }
1159
1160 /* get the complete list of modules to remove because of dependencies,
1161 * we are going also to remove all the imported (not implemented) modules
1162 * that are not used in any other module */
1163 mods = ly_set_new();
1164 ly_set_add(mods, mod, 0);
1165checkdependency:
Michal Vasko2d051a12017-04-21 09:28:57 +02001166 for (i = LY_INTERNAL_MODULE_COUNT; i < ctx->models.used; i++) {
Radek Krejci8c107fe2016-10-17 16:00:18 +02001167 mod = ctx->models.list[i]; /* shortcut */
1168 if (!mod) {
1169 /* skip modules already selected for removing */
1170 continue;
1171 }
1172
1173 /* check depndency of imported modules */
1174 for (j = 0; j < mod->imp_size; j++) {
1175 for (u = 0; u < mods->number; u++) {
1176 if (mod->imp[j].module == mods->set.g[u]) {
1177 /* module is importing some module to remove, so it must be also removed */
1178 ly_set_add(mods, mod, 0);
1179 ctx->models.list[i] = NULL;
1180 /* we have to start again because some of the already checked modules can
1181 * depend on the one we have just decided to remove */
1182 goto checkdependency;
1183 }
1184 }
1185 }
1186 /* check if the imported module is used in any module supposed to be kept */
1187 if (!mod->implemented) {
1188 imported = 0;
Michal Vasko2d051a12017-04-21 09:28:57 +02001189 for (o = LY_INTERNAL_MODULE_COUNT; o < ctx->models.used; o++) {
Radek Krejci8c107fe2016-10-17 16:00:18 +02001190 if (!ctx->models.list[o]) {
1191 /* skip modules already selected for removing */
1192 continue;
1193 }
1194 for (j = 0; j < ctx->models.list[o]->imp_size; j++) {
1195 if (ctx->models.list[o]->imp[j].module == mod) {
1196 /* the module is used in some other module not yet selected to be deleted */
1197 imported = 1;
1198 goto imported;
1199 }
1200 }
1201 }
1202imported:
1203 if (!imported) {
1204 /* module is not implemented and neither imported by any other module in context
1205 * which is supposed to be kept after this operation, so we are going to remove also
1206 * this useless module */
1207 ly_set_add(mods, mod, 0);
1208 ctx->models.list[i] = NULL;
1209 /* we have to start again, this time not because other module can depend on this one
Radek Krejci0ec51da2016-12-14 16:42:03 +01001210 * (we know that there is no such module), but because the module can import module
Radek Krejci8c107fe2016-10-17 16:00:18 +02001211 * that could became useless. If there are no imports, we can continue */
1212 if (mod->imp_size) {
1213 goto checkdependency;
1214 }
1215 }
1216 }
1217 }
1218
Radek Krejci8c107fe2016-10-17 16:00:18 +02001219
1220 /* consolidate the modules list */
Michal Vasko2d051a12017-04-21 09:28:57 +02001221 for (i = o = LY_INTERNAL_MODULE_COUNT; i < ctx->models.used; i++) {
Radek Krejci8c107fe2016-10-17 16:00:18 +02001222 if (ctx->models.list[o]) {
1223 /* used cell */
1224 o++;
1225 } else {
1226 /* the current output cell is empty, move here an input cell */
1227 ctx->models.list[o] = ctx->models.list[i];
1228 ctx->models.list[i] = NULL;
1229 }
1230 }
1231 /* get the last used cell to get know the number of used */
1232 while (!ctx->models.list[o]) {
1233 o--;
1234 }
1235 ctx->models.used = o + 1;
1236 ctx->models.module_set_id++;
1237
Radek Krejci85a54be2016-10-20 12:39:56 +02001238 /* maintain backlinks (start with internal ietf-yang-library which have leafs as possible targets of leafrefs */
Michal Vasko4be5fa22017-02-07 10:12:32 +01001239 ctx_modules_undo_backlinks(ctx, mods);
Radek Krejci85a54be2016-10-20 12:39:56 +02001240
1241 /* free the modules */
1242 for (u = 0; u < mods->number; u++) {
Radek Krejcib2541a32016-12-12 16:45:57 +01001243 /* remove the applied deviations and augments */
1244 lys_sub_module_remove_devs_augs((struct lys_module *)mods->set.g[u]);
Radek Krejci85a54be2016-10-20 12:39:56 +02001245 /* remove the module */
1246 lys_free((struct lys_module *)mods->set.g[u], private_destructor, 0);
1247 }
1248 ly_set_free(mods);
1249
Radek Krejci8c107fe2016-10-17 16:00:18 +02001250 return EXIT_SUCCESS;
1251}
1252
Radek Krejci85a54be2016-10-20 12:39:56 +02001253API void
1254ly_ctx_clean(struct ly_ctx *ctx, void (*private_destructor)(const struct lys_node *node, void *priv))
1255{
Radek Krejci85a54be2016-10-20 12:39:56 +02001256 if (!ctx) {
1257 return;
1258 }
1259
1260 /* models list */
Michal Vasko2d051a12017-04-21 09:28:57 +02001261 for (; ctx->models.used > LY_INTERNAL_MODULE_COUNT; ctx->models.used--) {
Radek Krejcifc8411a2017-02-03 10:26:05 +01001262 /* remove the applied deviations and augments */
Radek Krejcic436a232017-02-08 14:43:11 +01001263 lys_sub_module_remove_devs_augs(ctx->models.list[ctx->models.used - 1]);
Radek Krejcifc8411a2017-02-03 10:26:05 +01001264 /* remove the module */
Radek Krejcic436a232017-02-08 14:43:11 +01001265 lys_free(ctx->models.list[ctx->models.used - 1], private_destructor, 0);
Radek Krejcifc8411a2017-02-03 10:26:05 +01001266 /* clean it for safer future use */
Radek Krejcic436a232017-02-08 14:43:11 +01001267 ctx->models.list[ctx->models.used - 1] = NULL;
Radek Krejci85a54be2016-10-20 12:39:56 +02001268 }
Radek Krejci85a54be2016-10-20 12:39:56 +02001269 ctx->models.module_set_id++;
1270
Radek Krejci83a4bac2017-02-07 15:53:04 +01001271 /* maintain backlinks (actually done only with ietf-yang-library since its leafs can be target of leafref) */
Michal Vasko4be5fa22017-02-07 10:12:32 +01001272 ctx_modules_undo_backlinks(ctx, NULL);
Radek Krejci85a54be2016-10-20 12:39:56 +02001273}
1274
Michal Vaskod7957c02016-04-01 10:27:26 +02001275API const struct lys_module *
1276ly_ctx_get_module_iter(const struct ly_ctx *ctx, uint32_t *idx)
1277{
1278 if (!ctx || !idx) {
1279 ly_errno = LY_EINVAL;
1280 return NULL;
1281 }
1282
Radek Krejci0ec51da2016-12-14 16:42:03 +01001283 for ( ; *idx < (unsigned)ctx->models.used; (*idx)++) {
1284 if (!ctx->models.list[(*idx)]->disabled) {
1285 return ctx->models.list[(*idx)++];
1286 }
1287 }
1288
1289 return NULL;
1290}
1291
1292API const struct lys_module *
1293ly_ctx_get_disabled_module_iter(const struct ly_ctx *ctx, uint32_t *idx)
1294{
1295 if (!ctx || !idx) {
1296 ly_errno = LY_EINVAL;
Michal Vaskod7957c02016-04-01 10:27:26 +02001297 return NULL;
1298 }
1299
Radek Krejci0ec51da2016-12-14 16:42:03 +01001300 for ( ; *idx < (unsigned)ctx->models.used; (*idx)++) {
1301 if (ctx->models.list[(*idx)]->disabled) {
1302 return ctx->models.list[(*idx)++];
1303 }
1304 }
1305
1306 return NULL;
Michal Vaskod7957c02016-04-01 10:27:26 +02001307}
1308
Michal Vasko209a6222015-10-16 09:51:07 +02001309static int
1310ylib_feature(struct lyd_node *parent, struct lys_module *cur_mod)
1311{
1312 int i, j;
1313
1314 /* module features */
1315 for (i = 0; i < cur_mod->features_size; ++i) {
1316 if (!(cur_mod->features[i].flags & LYS_FENABLED)) {
1317 continue;
1318 }
1319
Michal Vasko3e671b52015-10-23 16:23:15 +02001320 if (!lyd_new_leaf(parent, NULL, "feature", cur_mod->features[i].name)) {
Michal Vasko209a6222015-10-16 09:51:07 +02001321 return EXIT_FAILURE;
1322 }
1323 }
1324
1325 /* submodule features */
Radek Krejcic071c542016-01-27 14:57:51 +01001326 for (i = 0; i < cur_mod->inc_size && cur_mod->inc[i].submodule; ++i) {
Michal Vasko209a6222015-10-16 09:51:07 +02001327 for (j = 0; j < cur_mod->inc[i].submodule->features_size; ++j) {
1328 if (!(cur_mod->inc[i].submodule->features[j].flags & LYS_FENABLED)) {
1329 continue;
1330 }
1331
Michal Vasko3e671b52015-10-23 16:23:15 +02001332 if (!lyd_new_leaf(parent, NULL, "feature", cur_mod->inc[i].submodule->features[j].name)) {
Michal Vasko209a6222015-10-16 09:51:07 +02001333 return EXIT_FAILURE;
1334 }
1335 }
1336 }
1337
1338 return EXIT_SUCCESS;
1339}
1340
1341static int
Michal Vaskoff006c12016-02-17 11:15:19 +01001342ylib_deviation(struct lyd_node *parent, struct lys_module *cur_mod)
Michal Vasko97d8c6d2016-02-12 11:05:48 +01001343{
Michal Vasko89563fc2016-07-28 16:19:35 +02001344 uint32_t i = 0, j;
1345 const struct lys_module *mod;
Michal Vasko209a6222015-10-16 09:51:07 +02001346 struct lyd_node *cont;
Michal Vasko89563fc2016-07-28 16:19:35 +02001347 const char *ptr;
Michal Vasko209a6222015-10-16 09:51:07 +02001348
Michal Vasko89563fc2016-07-28 16:19:35 +02001349 if (cur_mod->deviated) {
1350 while ((mod = ly_ctx_get_module_iter(cur_mod->ctx, &i))) {
1351 if (mod == cur_mod) {
1352 continue;
Michal Vasko209a6222015-10-16 09:51:07 +02001353 }
Michal Vasko209a6222015-10-16 09:51:07 +02001354
Michal Vasko89563fc2016-07-28 16:19:35 +02001355 for (j = 0; j < mod->deviation_size; ++j) {
1356 ptr = strstr(mod->deviation[j].target_name, cur_mod->name);
1357 if (ptr && ptr[strlen(cur_mod->name)] == ':') {
1358 cont = lyd_new(parent, NULL, "deviation");
1359 if (!cont) {
1360 return EXIT_FAILURE;
1361 }
1362
1363 if (!lyd_new_leaf(cont, NULL, "name", mod->name)) {
1364 return EXIT_FAILURE;
1365 }
1366 if (!lyd_new_leaf(cont, NULL, "revision", (mod->rev_size ? mod->rev[0].date : ""))) {
1367 return EXIT_FAILURE;
1368 }
Michal Vasko0c2215b2016-08-25 14:18:43 +02001369
1370 break;
Michal Vasko89563fc2016-07-28 16:19:35 +02001371 }
Michal Vasko209a6222015-10-16 09:51:07 +02001372 }
1373 }
1374 }
1375
1376 return EXIT_SUCCESS;
1377}
1378
1379static int
1380ylib_submodules(struct lyd_node *parent, struct lys_module *cur_mod)
1381{
1382 int i;
Radek Krejcia77904e2016-02-25 16:23:45 +01001383 char *str;
Radek Krejcid9723912016-09-16 17:06:06 +02001384 struct lyd_node *item;
Michal Vasko209a6222015-10-16 09:51:07 +02001385
Radek Krejcic071c542016-01-27 14:57:51 +01001386 for (i = 0; i < cur_mod->inc_size && cur_mod->inc[i].submodule; ++i) {
Radek Krejcid9723912016-09-16 17:06:06 +02001387 item = lyd_new(parent, NULL, "submodule");
Radek Krejci6e05cea2015-12-10 16:34:37 +01001388 if (!item) {
Michal Vasko209a6222015-10-16 09:51:07 +02001389 return EXIT_FAILURE;
1390 }
1391
Radek Krejci6e05cea2015-12-10 16:34:37 +01001392 if (!lyd_new_leaf(item, NULL, "name", cur_mod->inc[i].submodule->name)) {
Michal Vasko209a6222015-10-16 09:51:07 +02001393 return EXIT_FAILURE;
1394 }
Radek Krejci6e05cea2015-12-10 16:34:37 +01001395 if (!lyd_new_leaf(item, NULL, "revision", (cur_mod->inc[i].submodule->rev_size ?
Michal Vasko3e671b52015-10-23 16:23:15 +02001396 cur_mod->inc[i].submodule->rev[0].date : ""))) {
Michal Vasko209a6222015-10-16 09:51:07 +02001397 return EXIT_FAILURE;
1398 }
Radek Krejcia77904e2016-02-25 16:23:45 +01001399 if (cur_mod->inc[i].submodule->filepath) {
Radek Krejci95aa2012016-03-03 11:21:09 +01001400 if (asprintf(&str, "file://%s", cur_mod->inc[i].submodule->filepath) == -1) {
Radek Krejcia77904e2016-02-25 16:23:45 +01001401 LOGMEM;
1402 return EXIT_FAILURE;
Radek Krejci6e65af92016-03-07 12:48:19 +01001403 } else if (!lyd_new_leaf(item, NULL, "schema", str)) {
Radek Krejci19f9ede2016-02-25 16:29:21 +01001404 free(str);
Radek Krejcia77904e2016-02-25 16:23:45 +01001405 return EXIT_FAILURE;
1406 }
Radek Krejci19f9ede2016-02-25 16:29:21 +01001407 free(str);
Michal Vasko209a6222015-10-16 09:51:07 +02001408 }
1409 }
1410
1411 return EXIT_SUCCESS;
1412}
1413
1414API struct lyd_node *
1415ly_ctx_info(struct ly_ctx *ctx)
1416{
1417 int i;
1418 char id[8];
Radek Krejcia77904e2016-02-25 16:23:45 +01001419 char *str;
Michal Vasko1e62a092015-12-01 12:27:20 +01001420 const struct lys_module *mod;
Michal Vasko209a6222015-10-16 09:51:07 +02001421 struct lyd_node *root, *cont;
1422
Michal Vasko7eccc6c2016-03-24 14:56:33 +01001423 if (!ctx) {
1424 ly_errno = LY_EINVAL;
1425 return NULL;
1426 }
1427
Radek Krejcibd9e8d22016-02-03 14:11:48 +01001428 mod = ly_ctx_get_module(ctx, "ietf-yang-library", IETF_YANG_LIB_REV);
1429 if (!mod || !mod->data) {
1430 LOGINT;
Michal Vasko209a6222015-10-16 09:51:07 +02001431 return NULL;
1432 }
1433
Radek Krejcibd9e8d22016-02-03 14:11:48 +01001434 root = lyd_new(NULL, mod, "modules-state");
Michal Vasko209a6222015-10-16 09:51:07 +02001435 if (!root) {
1436 return NULL;
1437 }
1438
1439 for (i = 0; i < ctx->models.used; ++i) {
Radek Krejci0ec51da2016-12-14 16:42:03 +01001440 if (ctx->models.list[i]->disabled) {
1441 /* skip the disabled modules */
1442 continue;
1443 }
1444
Michal Vasko209a6222015-10-16 09:51:07 +02001445 cont = lyd_new(root, NULL, "module");
1446 if (!cont) {
1447 lyd_free(root);
1448 return NULL;
1449 }
1450
Michal Vasko3e671b52015-10-23 16:23:15 +02001451 if (!lyd_new_leaf(cont, NULL, "name", ctx->models.list[i]->name)) {
Michal Vasko209a6222015-10-16 09:51:07 +02001452 lyd_free(root);
1453 return NULL;
1454 }
Michal Vasko3e671b52015-10-23 16:23:15 +02001455 if (!lyd_new_leaf(cont, NULL, "revision", (ctx->models.list[i]->rev_size ?
Michal Vasko209a6222015-10-16 09:51:07 +02001456 ctx->models.list[i]->rev[0].date : ""))) {
1457 lyd_free(root);
1458 return NULL;
1459 }
Radek Krejcia77904e2016-02-25 16:23:45 +01001460 if (ctx->models.list[i]->filepath) {
Radek Krejci15412ca2016-03-03 11:16:52 +01001461 if (asprintf(&str, "file://%s", ctx->models.list[i]->filepath) == -1) {
Radek Krejcia77904e2016-02-25 16:23:45 +01001462 LOGMEM;
1463 lyd_free(root);
1464 return NULL;
1465 } else if (!lyd_new_leaf(cont, NULL, "schema", str)) {
Radek Krejci19f9ede2016-02-25 16:29:21 +01001466 free(str);
Radek Krejcia77904e2016-02-25 16:23:45 +01001467 lyd_free(root);
1468 return NULL;
1469 }
Radek Krejci19f9ede2016-02-25 16:29:21 +01001470 free(str);
Michal Vasko209a6222015-10-16 09:51:07 +02001471 }
Michal Vasko3e671b52015-10-23 16:23:15 +02001472 if (!lyd_new_leaf(cont, NULL, "namespace", ctx->models.list[i]->ns)) {
Michal Vasko209a6222015-10-16 09:51:07 +02001473 lyd_free(root);
1474 return NULL;
1475 }
1476 if (ylib_feature(cont, ctx->models.list[i])) {
1477 lyd_free(root);
1478 return NULL;
1479 }
Michal Vaskoff006c12016-02-17 11:15:19 +01001480 if (ylib_deviation(cont, ctx->models.list[i])) {
Michal Vasko209a6222015-10-16 09:51:07 +02001481 lyd_free(root);
1482 return NULL;
1483 }
1484 if (ctx->models.list[i]->implemented
Radek Krejcibd9e8d22016-02-03 14:11:48 +01001485 && !lyd_new_leaf(cont, NULL, "conformance-type", "implement")) {
Michal Vasko209a6222015-10-16 09:51:07 +02001486 lyd_free(root);
1487 return NULL;
1488 }
1489 if (!ctx->models.list[i]->implemented
Radek Krejcibd9e8d22016-02-03 14:11:48 +01001490 && !lyd_new_leaf(cont, NULL, "conformance-type", "import")) {
Michal Vasko209a6222015-10-16 09:51:07 +02001491 lyd_free(root);
1492 return NULL;
1493 }
1494 if (ylib_submodules(cont, ctx->models.list[i])) {
1495 lyd_free(root);
1496 return NULL;
1497 }
1498 }
1499
1500 sprintf(id, "%u", ctx->models.module_set_id);
Michal Vasko3e671b52015-10-23 16:23:15 +02001501 if (!lyd_new_leaf(root, mod, "module-set-id", id)) {
Michal Vasko209a6222015-10-16 09:51:07 +02001502 lyd_free(root);
1503 return NULL;
1504 }
1505
Michal Vaskocdb90172016-09-13 09:34:36 +02001506 if (lyd_validate(&root, LYD_OPT_NOSIBLINGS, NULL)) {
Michal Vasko209a6222015-10-16 09:51:07 +02001507 lyd_free(root);
1508 return NULL;
1509 }
1510
1511 return root;
1512}
Michal Vasko3edeaf72016-02-11 13:17:43 +01001513
1514API const struct lys_node *
Michal Vasko3547c532016-03-14 09:40:50 +01001515ly_ctx_get_node(struct ly_ctx *ctx, const struct lys_node *start, const char *nodeid)
Michal Vasko3edeaf72016-02-11 13:17:43 +01001516{
Michal Vaskoe733d682016-03-14 09:08:27 +01001517 const struct lys_node *node;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001518
Michal Vasko3547c532016-03-14 09:40:50 +01001519 if (!ctx || !nodeid || ((nodeid[0] != '/') && !start)) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001520 ly_errno = LY_EINVAL;
1521 return NULL;
1522 }
1523
Michal Vaskoe733d682016-03-14 09:08:27 +01001524 /* sets error and everything */
Michal Vasko8d26e5c2016-09-08 10:03:49 +02001525 node = resolve_json_nodeid(nodeid, ctx, start);
Michal Vasko3edeaf72016-02-11 13:17:43 +01001526
Michal Vaskoe733d682016-03-14 09:08:27 +01001527 return node;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001528}