blob: e52e8a4922618441588760e4100457990a024964 [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 Krejci532e5e92017-02-22 12:59:24 +010051#define INTERNAL_MODULES_COUNT 5
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;
58} internal_modules[INTERNAL_MODULES_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 Krejcid9723912016-09-16 17:06:06 +020063 {"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 +020064};
65
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020066API struct ly_ctx *
67ly_ctx_new(const char *search_dir)
Radek Krejcida04f4a2015-05-21 12:54:09 +020068{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020069 struct ly_ctx *ctx;
Michal Vasko7d7de952016-05-02 17:13:14 +020070 struct lys_module *module;
Michal Vasko70b6d692015-08-03 14:05:59 +020071 char *cwd;
Radek Krejci03203412016-06-23 15:20:53 +020072 int i;
Radek Krejcida04f4a2015-05-21 12:54:09 +020073
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020074 ctx = calloc(1, sizeof *ctx);
75 if (!ctx) {
76 LOGMEM;
77 return NULL;
78 }
Radek Krejcida04f4a2015-05-21 12:54:09 +020079
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020080 /* dictionary */
81 lydict_init(&ctx->dict);
Radek Krejcida04f4a2015-05-21 12:54:09 +020082
Radek Krejci858ad952017-01-04 11:16:32 +010083 /* plugins */
Radek Krejci858ad952017-01-04 11:16:32 +010084 lyext_load_plugins();
85
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020086 /* models list */
87 ctx->models.list = calloc(16, sizeof *ctx->models.list);
Michal Vasko253035f2015-12-17 16:58:13 +010088 if (!ctx->models.list) {
89 LOGMEM;
90 free(ctx);
91 return NULL;
92 }
Radek Krejci37d02632017-02-21 14:14:11 +010093 ext_plugins_ref++;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020094 ctx->models.used = 0;
95 ctx->models.size = 16;
96 if (search_dir) {
97 cwd = get_current_dir_name();
98 if (chdir(search_dir)) {
99 LOGERR(LY_ESYS, "Unable to use search directory \"%s\" (%s)",
100 search_dir, strerror(errno));
101 free(cwd);
Radek Krejcifa0b5e02016-02-04 13:57:03 +0100102 ly_ctx_destroy(ctx, NULL);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200103 return NULL;
104 }
105 ctx->models.search_path = get_current_dir_name();
Radek Krejci15412ca2016-03-03 11:16:52 +0100106 if (chdir(cwd)) {
107 LOGWRN("Unable to return back to working directory \"%s\" (%s)",
108 cwd, strerror(errno));
109 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200110 free(cwd);
111 }
Michal Vasko14719b22015-08-03 12:47:55 +0200112 ctx->models.module_set_id = 1;
113
Radek Krejci03203412016-06-23 15:20:53 +0200114 /* load internal modules */
115 for (i = 0; i < INTERNAL_MODULES_COUNT; i++) {
116 module = (struct lys_module *)lys_parse_mem(ctx, internal_modules[i].data, internal_modules[i].format);
117 if (!module) {
118 ly_ctx_destroy(ctx, NULL);
119 return NULL;
120 }
121 module->implemented = internal_modules[i].implemented;
Michal Vasko8d054e42015-08-03 12:42:06 +0200122 }
Radek Krejcida04f4a2015-05-21 12:54:09 +0200123
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200124 return ctx;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200125}
126
Radek Krejci69333c92017-03-17 16:14:43 +0100127static struct ly_ctx *
128ly_ctx_new_yl_common(const char *search_dir, const char *input, LYD_FORMAT format,
129 struct lyd_node* (*parser_func)(struct ly_ctx*, const char*, LYD_FORMAT, int,...))
130{
131 unsigned int u;
132 struct lyd_node *module, *node;
133 const char *name, *revision;
Radek Krejci5cb217d2017-03-25 16:07:52 -0500134 struct ly_set features = {0, 0, {NULL}};
Radek Krejci69333c92017-03-17 16:14:43 +0100135 const struct lys_module *mod;
136 struct lyd_node *yltree = NULL;
137 struct ly_ctx *ctx = NULL;
138
139 /* create empty (with internal modules including ietf-yang-library) context */
140 ctx = ly_ctx_new(search_dir);
141 if (!ctx) {
142 goto error;
143 }
144
145 /* parse yang library data tree */
146 yltree = parser_func(ctx, input, format, LYD_OPT_DATA, NULL);
147 if (!yltree) {
148 goto error;
149 }
150
151 /* process the data tree */
152 LY_TREE_FOR(yltree->child, module) {
153 if (module->schema->nodetype == LYS_LEAF) {
154 /* module-set-id - ignore it */
155 continue;
156 }
157
158 /* initiate */
159 name = NULL;
160 revision = NULL;
161 ly_set_clean(&features);
162
163 LY_TREE_FOR(module->child, node) {
164 if (!strcmp(node->schema->name, "name")) {
165 name = ((struct lyd_node_leaf_list*)node)->value_str;
166 } else if (!strcmp(node->schema->name, "revision")) {
167 revision = ((struct lyd_node_leaf_list*)node)->value_str;
168 } else if (!strcmp(node->schema->name, "feature")) {
169 ly_set_add(&features, node, LY_SET_OPT_USEASLIST);
170 } else if (!strcmp(node->schema->name, "conformance-type") &&
171 ((struct lyd_node_leaf_list*)node)->value.enm->value) {
172 /* imported module - skip it, it will be loaded as a side effect
173 * of loading another module */
174 goto next_module;
175 }
176 }
177
178 /* use the gathered data to load the module */
179 mod = ly_ctx_load_module(ctx, name, revision);
180 if (!mod) {
181 LOGERR(LY_EINVAL, "Unable to load module specified by yang library data.");
182 goto error;
183 }
184
185 /* set features */
186 for (u = 0; u < features.number; u++) {
187 lys_features_enable(mod, ((struct lyd_node_leaf_list*)features.set.d[u])->value_str);
188 }
189
190next_module:;
191 }
192
193 if (0) {
194 /* skip context destroy in case of success */
195error:
196 ly_ctx_destroy(ctx, NULL);
197 ctx = NULL;
198 }
199
200 /* cleanup */
201 if (yltree) {
202 /* yang library data tree */
203 lyd_free_withsiblings(yltree);
204 }
205
206 return ctx;
207}
208
209API struct ly_ctx *
210ly_ctx_new_ylpath(const char *search_dir, const char *path, LYD_FORMAT format)
211{
212 return ly_ctx_new_yl_common(search_dir, path, format, lyd_parse_path);
213}
214
215API struct ly_ctx *
216ly_ctx_new_ylmem(const char *search_dir, const char *data, LYD_FORMAT format)
217{
218 return ly_ctx_new_yl_common(search_dir, data, format, lyd_parse_mem);
219}
220
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200221API void
Radek Krejci819dd4b2017-03-07 15:35:48 +0100222ly_ctx_set_allimplemented(struct ly_ctx *ctx)
223{
224 if (!ctx) {
225 return;
226 }
227
228 ctx->models.flags |= LY_CTX_ALLIMPLEMENTED;
229}
230
231API void
232ly_ctx_unset_allimplemented(struct ly_ctx *ctx)
233{
234 if (!ctx) {
235 return;
236 }
237
238 ctx->models.flags &= ~LY_CTX_ALLIMPLEMENTED;
239}
240
241API void
Michal Vasko60ba9a62015-07-03 14:42:31 +0200242ly_ctx_set_searchdir(struct ly_ctx *ctx, const char *search_dir)
243{
244 char *cwd;
245
246 if (!ctx) {
247 return;
248 }
249
250 if (search_dir) {
251 cwd = get_current_dir_name();
252 if (chdir(search_dir)) {
253 LOGERR(LY_ESYS, "Unable to use search directory \"%s\" (%s)",
254 search_dir, strerror(errno));
255 free(cwd);
256 return;
257 }
Michal Vasko3eff9322015-11-10 11:02:30 +0100258 free(ctx->models.search_path);
Michal Vasko60ba9a62015-07-03 14:42:31 +0200259 ctx->models.search_path = get_current_dir_name();
Michal Vasko3eff9322015-11-10 11:02:30 +0100260
Radek Krejci15412ca2016-03-03 11:16:52 +0100261 if (chdir(cwd)) {
262 LOGWRN("Unable to return back to working directory \"%s\" (%s)",
263 cwd, strerror(errno));
264 }
Michal Vasko60ba9a62015-07-03 14:42:31 +0200265 free(cwd);
266 } else {
267 free(ctx->models.search_path);
268 ctx->models.search_path = NULL;
269 }
270}
271
Radek Krejcib081d8d2015-10-21 16:29:07 +0200272API const char *
Michal Vasko1e62a092015-12-01 12:27:20 +0100273ly_ctx_get_searchdir(const struct ly_ctx *ctx)
Radek Krejci5a797572015-10-21 15:45:45 +0200274{
Radek Krejciee554172016-12-14 10:29:06 +0100275 if (!ctx) {
276 ly_errno = LY_EINVAL;
277 return NULL;
278 }
Radek Krejci5a797572015-10-21 15:45:45 +0200279 return ctx->models.search_path;
280}
281
Michal Vasko60ba9a62015-07-03 14:42:31 +0200282API void
Radek Krejcifa0b5e02016-02-04 13:57:03 +0100283ly_ctx_destroy(struct ly_ctx *ctx, void (*private_destructor)(const struct lys_node *node, void *priv))
Radek Krejcida04f4a2015-05-21 12:54:09 +0200284{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200285 if (!ctx) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200286 return;
287 }
Radek Krejcida04f4a2015-05-21 12:54:09 +0200288
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200289 /* models list */
Radek Krejcic436a232017-02-08 14:43:11 +0100290 for (; ctx->models.used > 0; ctx->models.used--) {
Radek Krejcifc8411a2017-02-03 10:26:05 +0100291 /* remove the applied deviations and augments */
Radek Krejcic436a232017-02-08 14:43:11 +0100292 lys_sub_module_remove_devs_augs(ctx->models.list[ctx->models.used - 1]);
Radek Krejcifc8411a2017-02-03 10:26:05 +0100293 /* remove the module */
Radek Krejcic436a232017-02-08 14:43:11 +0100294 lys_free(ctx->models.list[ctx->models.used - 1], private_destructor, 0);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200295 }
296 free(ctx->models.search_path);
297 free(ctx->models.list);
Radek Krejcida04f4a2015-05-21 12:54:09 +0200298
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200299 /* dictionary */
300 lydict_clean(&ctx->dict);
Radek Krejcida04f4a2015-05-21 12:54:09 +0200301
Radek Krejci858ad952017-01-04 11:16:32 +0100302 /* plugins - will be removed only if this is the last context */
303 ext_plugins_ref--;
304 lyext_clean_plugins();
305
Radek Krejci8b76a4a2016-10-26 10:02:32 +0200306 /* clean the error list */
Radek Krejci00a0e712016-10-26 10:24:46 +0200307 ly_err_clean(0);
Radek Krejci8b76a4a2016-10-26 10:02:32 +0200308
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200309 free(ctx);
Radek Krejcida04f4a2015-05-21 12:54:09 +0200310}
311
Michal Vasko1e62a092015-12-01 12:27:20 +0100312API const struct lys_submodule *
Radek Krejci62f0da72016-03-07 11:35:43 +0100313ly_ctx_get_submodule2(const struct lys_module *main_module, const char *submodule)
314{
Radek Krejcid4c1d0f2017-01-19 16:11:38 +0100315 const struct lys_submodule *result;
Radek Krejci62f0da72016-03-07 11:35:43 +0100316 int i;
317
318 if (!main_module || !submodule) {
319 ly_errno = LY_EINVAL;
320 return NULL;
321 }
322
323 /* search in submodules list */
324 for (i = 0; i < main_module->inc_size; i++) {
325 result = main_module->inc[i].submodule;
Radek Krejcid4c1d0f2017-01-19 16:11:38 +0100326 if (ly_strequal(submodule, result->name, 0)) {
Radek Krejci62f0da72016-03-07 11:35:43 +0100327 return result;
328 }
Radek Krejcid4c1d0f2017-01-19 16:11:38 +0100329
330 /* in YANG 1.1 all the submodules must be included in the main module, so we are done.
331 * YANG 1.0 allows (is unclear about denying it) to include a submodule only in another submodule
332 * but when libyang parses such a module it adds the include into the main module so we are also done.
333 */
Radek Krejci62f0da72016-03-07 11:35:43 +0100334 }
335
Radek Krejcid4c1d0f2017-01-19 16:11:38 +0100336
Radek Krejci62f0da72016-03-07 11:35:43 +0100337 return NULL;
338}
339
340API const struct lys_submodule *
Michal Vaskof6d94c62016-04-05 11:21:54 +0200341ly_ctx_get_submodule(const struct ly_ctx *ctx, const char *module, const char *revision, const char *submodule,
342 const char *sub_revision)
Radek Krejciefaeba32015-05-27 14:30:57 +0200343{
Radek Krejcie7973552016-03-07 08:12:01 +0100344 const struct lys_module *mainmod;
Michal Vaskof6d94c62016-04-05 11:21:54 +0200345 const struct lys_submodule *ret = NULL, *submod;
346 uint32_t idx = 0;
Radek Krejciefaeba32015-05-27 14:30:57 +0200347
Michal Vaskof6d94c62016-04-05 11:21:54 +0200348 if (!ctx || !submodule || (revision && !module)) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200349 ly_errno = LY_EINVAL;
350 return NULL;
351 }
Radek Krejciefaeba32015-05-27 14:30:57 +0200352
Michal Vaskof6d94c62016-04-05 11:21:54 +0200353 while ((mainmod = ly_ctx_get_module_iter(ctx, &idx))) {
354 if (module && strcmp(mainmod->name, module)) {
355 /* main module name does not match */
356 continue;
357 }
358
359 if (revision && (!mainmod->rev || strcmp(revision, mainmod->rev[0].date))) {
360 /* main module revision does not match */
361 continue;
362 }
363
364 submod = ly_ctx_get_submodule2(mainmod, submodule);
365 if (!submod) {
366 continue;
367 }
368
369 if (!sub_revision) {
370 /* store only if newer */
371 if (ret) {
372 if (submod->rev && (!ret->rev || (strcmp(submod->rev[0].date, ret->rev[0].date) > 0))) {
373 ret = submod;
374 }
375 } else {
376 ret = submod;
377 }
378 } else {
379 /* store only if revision matches, we are done if it does */
380 if (!submod->rev) {
381 continue;
382 } else if (!strcmp(sub_revision, submod->rev[0].date)) {
383 ret = submod;
384 break;
385 }
386 }
Radek Krejcia7533f22016-03-07 07:37:45 +0100387 }
Radek Krejcic071c542016-01-27 14:57:51 +0100388
Michal Vaskof6d94c62016-04-05 11:21:54 +0200389 return ret;
Radek Krejciefaeba32015-05-27 14:30:57 +0200390}
391
Michal Vasko1e62a092015-12-01 12:27:20 +0100392static const struct lys_module *
Radek Krejci0ec51da2016-12-14 16:42:03 +0100393ly_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 +0200394{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200395 int i;
Radek Krejcib8048692015-08-05 13:36:34 +0200396 struct lys_module *result = NULL;
Radek Krejciefaeba32015-05-27 14:30:57 +0200397
Radek Krejcifd4e6e32015-08-10 15:00:51 +0200398 if (!ctx || !key) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200399 ly_errno = LY_EINVAL;
400 return NULL;
401 }
Radek Krejciefaeba32015-05-27 14:30:57 +0200402
Radek Krejcidce51452015-06-16 15:20:08 +0200403 for (i = 0; i < ctx->models.used; i++) {
Radek Krejci0ec51da2016-12-14 16:42:03 +0100404 if (!with_disabled && ctx->models.list[i]->disabled) {
405 /* skip the disabled modules */
406 continue;
407 }
Radek Krejcifd4e6e32015-08-10 15:00:51 +0200408 /* use offset to get address of the pointer to string (char**), remember that offset is in
409 * bytes, so we have to cast the pointer to the module to (char*), finally, we want to have
410 * string not the pointer to string
411 */
412 if (!ctx->models.list[i] || strcmp(key, *(char**)(((char*)ctx->models.list[i]) + offset))) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200413 continue;
414 }
Radek Krejciefaeba32015-05-27 14:30:57 +0200415
Radek Krejcif647e612015-07-30 11:36:07 +0200416 if (!revision) {
417 /* compare revisons and remember the newest one */
418 if (result) {
419 if (!ctx->models.list[i]->rev_size) {
420 /* the current have no revision, keep the previous with some revision */
421 continue;
422 }
423 if (result->rev_size && strcmp(ctx->models.list[i]->rev[0].date, result->rev[0].date) < 0) {
424 /* the previous found matching module has a newer revision */
425 continue;
426 }
427 }
428
429 /* remember the current match and search for newer version */
430 result = ctx->models.list[i];
431 } else {
432 if (ctx->models.list[i]->rev_size && !strcmp(revision, ctx->models.list[i]->rev[0].date)) {
433 /* matching revision */
Michal Vasko97586502015-08-12 14:32:18 +0200434 result = ctx->models.list[i];
435 break;
Radek Krejcif647e612015-07-30 11:36:07 +0200436 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200437 }
438 }
Radek Krejciefaeba32015-05-27 14:30:57 +0200439
Radek Krejcif647e612015-07-30 11:36:07 +0200440 return result;
Radek Krejcifd4e6e32015-08-10 15:00:51 +0200441
442}
443
Michal Vasko1e62a092015-12-01 12:27:20 +0100444API const struct lys_module *
445ly_ctx_get_module_by_ns(const struct ly_ctx *ctx, const char *ns, const char *revision)
Radek Krejcifd4e6e32015-08-10 15:00:51 +0200446{
Radek Krejci0ec51da2016-12-14 16:42:03 +0100447 return ly_ctx_get_module_by(ctx, ns, offsetof(struct lys_module, ns), revision, 0);
Radek Krejcifd4e6e32015-08-10 15:00:51 +0200448}
449
Michal Vasko1e62a092015-12-01 12:27:20 +0100450API const struct lys_module *
451ly_ctx_get_module(const struct ly_ctx *ctx, const char *name, const char *revision)
Radek Krejcifd4e6e32015-08-10 15:00:51 +0200452{
Radek Krejci0ec51da2016-12-14 16:42:03 +0100453 return ly_ctx_get_module_by(ctx, name, offsetof(struct lys_module, name), revision, 0);
Radek Krejcida04f4a2015-05-21 12:54:09 +0200454}
Michal Vasko3ec07dc2015-06-30 15:51:30 +0200455
Radek Krejci21601a32016-03-07 11:39:27 +0100456API const struct lys_module *
457ly_ctx_get_module_older(const struct ly_ctx *ctx, const struct lys_module *module)
458{
459 int i;
460 const struct lys_module *result = NULL, *iter;
461
462 if (!ctx || !module || !module->rev_size) {
463 ly_errno = LY_EINVAL;
464 return NULL;
465 }
466
467
468 for (i = 0; i < ctx->models.used; i++) {
469 iter = ctx->models.list[i];
Radek Krejci0ec51da2016-12-14 16:42:03 +0100470 if (iter->disabled) {
471 /* skip the disabled modules */
472 continue;
473 }
Radek Krejci21601a32016-03-07 11:39:27 +0100474 if (iter == module || !iter->rev_size) {
475 /* iter is the module itself or iter has no revision */
476 continue;
477 }
478 if (!ly_strequal(module->name, iter->name, 0)) {
479 /* different module */
480 continue;
481 }
482 if (strcmp(iter->rev[0].date, module->rev[0].date) < 0) {
483 /* iter is older than module */
484 if (result) {
485 if (strcmp(iter->rev[0].date, result->rev[0].date) > 0) {
486 /* iter is newer than current result */
487 result = iter;
488 }
489 } else {
490 result = iter;
491 }
492 }
493 }
494
495 return result;
496}
497
Michal Vasko99b0aad2015-12-01 12:28:51 +0100498API void
Michal Vaskoca28aab2017-01-13 13:50:12 +0100499ly_ctx_set_module_imp_clb(struct ly_ctx *ctx, ly_module_imp_clb clb, void *user_data)
Michal Vasko82465962015-11-10 11:03:11 +0100500{
Michal Vaskof53187d2017-01-13 13:23:14 +0100501 ctx->imp_clb = clb;
502 ctx->imp_clb_data = user_data;
Michal Vasko99b0aad2015-12-01 12:28:51 +0100503}
504
Michal Vaskof53187d2017-01-13 13:23:14 +0100505API ly_module_imp_clb
Michal Vaskoca28aab2017-01-13 13:50:12 +0100506ly_ctx_get_module_imp_clb(const struct ly_ctx *ctx, void **user_data)
Michal Vasko99b0aad2015-12-01 12:28:51 +0100507{
Radek Krejciee554172016-12-14 10:29:06 +0100508 if (!ctx) {
509 ly_errno = LY_EINVAL;
510 return NULL;
511 }
512
Michal Vasko99b0aad2015-12-01 12:28:51 +0100513 if (user_data) {
Michal Vaskof53187d2017-01-13 13:23:14 +0100514 *user_data = ctx->imp_clb_data;
Michal Vasko99b0aad2015-12-01 12:28:51 +0100515 }
Michal Vaskof53187d2017-01-13 13:23:14 +0100516 return ctx->imp_clb;
517}
518
519API void
Michal Vaskoca28aab2017-01-13 13:50:12 +0100520ly_ctx_set_module_data_clb(struct ly_ctx *ctx, ly_module_data_clb clb, void *user_data)
Michal Vaskof53187d2017-01-13 13:23:14 +0100521{
522 ctx->data_clb = clb;
523 ctx->data_clb_data = user_data;
524}
525
526API ly_module_data_clb
Michal Vaskoca28aab2017-01-13 13:50:12 +0100527ly_ctx_get_module_data_clb(const struct ly_ctx *ctx, void **user_data)
Michal Vaskof53187d2017-01-13 13:23:14 +0100528{
529 if (user_data) {
530 *user_data = ctx->data_clb_data;
531 }
532 return ctx->data_clb;
Michal Vasko99b0aad2015-12-01 12:28:51 +0100533}
534
Radek Krejcibf4e4652016-10-21 15:44:13 +0200535const struct lys_module *
Michal Vasko84475152016-07-25 16:16:25 +0200536ly_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 +0200537 int implement, struct unres_schema *unres)
Michal Vasko99b0aad2015-12-01 12:28:51 +0100538{
Radek Krejcibf4e4652016-10-21 15:44:13 +0200539 const struct lys_module *mod;
Michal Vasko99b0aad2015-12-01 12:28:51 +0100540 char *module_data;
Radek Krejci03203412016-06-23 15:20:53 +0200541 int i;
Michal Vaskod3e975b2016-03-03 15:40:21 +0100542 void (*module_data_free)(void *module_data) = NULL;
Michal Vasko99b0aad2015-12-01 12:28:51 +0100543 LYS_INFORMAT format = LYS_IN_UNKNOWN;
Michal Vasko82465962015-11-10 11:03:11 +0100544
Michal Vasko84475152016-07-25 16:16:25 +0200545 if (!module) {
Radek Krejcibf4e4652016-10-21 15:44:13 +0200546 /* exception for internal modules */
Michal Vasko84475152016-07-25 16:16:25 +0200547 for (i = 0; i < INTERNAL_MODULES_COUNT; i++) {
548 if (ly_strequal(name, internal_modules[i].name, 0)) {
549 if (!revision || ly_strequal(revision, internal_modules[i].revision, 0)) {
550 /* return internal module */
551 return (struct lys_module *)ly_ctx_get_module(ctx, name, revision);
552 }
Radek Krejci03203412016-06-23 15:20:53 +0200553 }
554 }
Radek Krejcibf4e4652016-10-21 15:44:13 +0200555 if (revision) {
Radek Krejci0ec51da2016-12-14 16:42:03 +0100556 /* try to get the schema with the specific revision from the context,
557 * include the disabled modules in the search to avoid their duplication,
558 * they are enabled by the subsequent call to lys_set_implemented() */
559 for (i = INTERNAL_MODULES_COUNT, mod = NULL; i < ctx->models.used; i++) {
560 mod = ctx->models.list[i]; /* shortcut */
561 if (ly_strequal(name, mod->name, 0) && mod->rev_size && !strcmp(revision, mod->rev[0].date)) {
562 break;
563 }
564 mod = NULL;
565 }
Radek Krejcibf4e4652016-10-21 15:44:13 +0200566 if (mod) {
567 /* we get such a module, make it implemented */
568 if (lys_set_implemented(mod)) {
569 /* the schema cannot be implemented */
570 mod = NULL;
571 }
572 return mod;
573 }
574 }
Radek Krejci03203412016-06-23 15:20:53 +0200575 }
576
Michal Vaskof53187d2017-01-13 13:23:14 +0100577 if (ctx->imp_clb) {
Michal Vasko84475152016-07-25 16:16:25 +0200578 if (module) {
579 mod = lys_main_module(module);
Michal Vaskof53187d2017-01-13 13:23:14 +0100580 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 +0200581 } else {
Michal Vaskof53187d2017-01-13 13:23:14 +0100582 module_data = ctx->imp_clb(name, revision, NULL, NULL, ctx->imp_clb_data, &format, &module_data_free);
Michal Vasko84475152016-07-25 16:16:25 +0200583 }
Michal Vasko99b0aad2015-12-01 12:28:51 +0100584 if (!module_data) {
Radek Krejcibf4e4652016-10-21 15:44:13 +0200585 if (module || revision) {
586 /* we already know that the specified revision is not present in context, and we have no other
587 * option in case of submodules */
588 LOGERR(LY_ESYS, "User module retrieval callback failed!");
589 return NULL;
590 } else {
591 /* get the newest revision from the context */
Radek Krejci0ec51da2016-12-14 16:42:03 +0100592 mod = ly_ctx_get_module_by(ctx, name, offsetof(struct lys_module, name), revision, 1);
593 if (mod && mod->disabled) {
594 /* enable the required module */
595 lys_set_enabled(mod);
596 }
597 return mod;
Radek Krejcibf4e4652016-10-21 15:44:13 +0200598 }
Michal Vasko82465962015-11-10 11:03:11 +0100599 }
Michal Vasko84475152016-07-25 16:16:25 +0200600
601 if (module) {
Michal Vasko5b998712017-01-26 10:34:06 +0100602 mod = (struct lys_module *)lys_sub_parse_mem(module, module_data, format, unres);
Michal Vasko84475152016-07-25 16:16:25 +0200603 } else {
604 mod = (struct lys_module *)lys_parse_mem(ctx, module_data, format);
605 }
606
Michal Vasko99b0aad2015-12-01 12:28:51 +0100607 if (module_data_free) {
608 module_data_free(module_data);
Michal Vasko82465962015-11-10 11:03:11 +0100609 }
Michal Vasko99b0aad2015-12-01 12:28:51 +0100610 } else {
Michal Vasko58e5f3e2016-07-28 11:06:34 +0200611 mod = lyp_search_file(ctx, module, name, revision, implement, unres);
Michal Vasko82465962015-11-10 11:03:11 +0100612 }
613
Michal Vasko84475152016-07-25 16:16:25 +0200614 return mod;
615}
616
617API const struct lys_module *
618ly_ctx_load_module(struct ly_ctx *ctx, const char *name, const char *revision)
619{
620 if (!ctx || !name) {
621 ly_errno = LY_EINVAL;
622 return NULL;
623 }
624
Michal Vasko58e5f3e2016-07-28 11:06:34 +0200625 return ly_ctx_load_sub_module(ctx, NULL, name, revision, 1, NULL);
Michal Vasko82465962015-11-10 11:03:11 +0100626}
627
Radek Krejci85a54be2016-10-20 12:39:56 +0200628/*
629 * mods - set of removed modules, if NULL all modules are supposed to be removed so any backlink is invalid
630 */
Michal Vasko4be5fa22017-02-07 10:12:32 +0100631static void
632ctx_modules_undo_backlinks(struct ly_ctx *ctx, struct ly_set *mods)
Radek Krejci85a54be2016-10-20 12:39:56 +0200633{
634 int o;
635 uint8_t j;
636 unsigned int u, v;
637 struct lys_module *mod;
638 struct lys_node *elem, *next;
639 struct lys_node_leaf *leaf;
640
641 /* maintain backlinks (start with internal ietf-yang-library which have leafs as possible targets of leafrefs */
642 for (o = INTERNAL_MODULES_COUNT - 1; o < ctx->models.used; o++) {
643 mod = ctx->models.list[o]; /* shortcut */
644
645 /* 1) features */
646 for (j = 0; j < mod->features_size; j++) {
647 if (!mod->features[j].depfeatures) {
648 continue;
649 }
650 for (v = 0; v < mod->features[j].depfeatures->number; v++) {
651 if (!mods || ly_set_contains(mods, ((struct lys_feature *)mod->features[j].depfeatures->set.g[v])->module) != -1) {
652 /* depending feature is in module to remove */
653 ly_set_rm_index(mod->features[j].depfeatures, v);
654 v--;
655 }
656 }
657 if (!mod->features[j].depfeatures->number) {
658 /* all backlinks removed */
659 ly_set_free(mod->features[j].depfeatures);
660 mod->features[j].depfeatures = NULL;
661 }
662 }
Michal Vasko4be5fa22017-02-07 10:12:32 +0100663
664 /* 2) identities */
Radek Krejci85a54be2016-10-20 12:39:56 +0200665 for (u = 0; u < mod->ident_size; u++) {
666 if (!mod->ident[u].der) {
667 continue;
668 }
669 for (v = 0; v < mod->ident[u].der->number; v++) {
670 if (!mods || ly_set_contains(mods, ((struct lys_ident *)mod->ident[u].der->set.g[v])->module) != -1) {
671 /* derived identity is in module to remove */
672 ly_set_rm_index(mod->ident[u].der, v);
673 v--;
674 }
675 }
676 if (!mod->ident[u].der->number) {
677 /* all backlinks removed */
678 ly_set_free(mod->ident[u].der);
679 mod->ident[u].der = NULL;
680 }
681 }
682
Michal Vasko4be5fa22017-02-07 10:12:32 +0100683 /* 3) leafrefs */
Radek Krejci85a54be2016-10-20 12:39:56 +0200684 for (elem = next = mod->data; elem; elem = next) {
685 if (elem->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
686 leaf = (struct lys_node_leaf *)elem; /* shortcut */
687 if (leaf->backlinks) {
688 if (!mods) {
689 /* remove all backlinks */
690 ly_set_free(leaf->backlinks);
691 leaf->backlinks = NULL;
692 } else {
693 for (v = 0; v < leaf->backlinks->number; v++) {
694 if (ly_set_contains(mods, leaf->backlinks->set.s[v]->module) != -1) {
695 /* derived identity is in module to remove */
696 ly_set_rm_index(leaf->backlinks, v);
697 v--;
698 }
699 }
700 if (!leaf->backlinks->number) {
701 /* all backlinks removed */
702 ly_set_free(leaf->backlinks);
703 leaf->backlinks = NULL;
704 }
705 }
706 }
707 }
708
709 /* select next element to process */
710 next = elem->child;
711 /* child exception for leafs, leaflists, anyxml and groupings */
712 if (elem->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA | LYS_GROUPING)) {
713 next = NULL;
714 }
715 if (!next) {
716 /* no children, try siblings */
717 next = elem->next;
718 }
719 while (!next) {
720 /* parent is already processed, go to its sibling */
721 elem = lys_parent(elem);
722 if (!elem) {
723 /* we are done, no next element to process */
724 break;
725 }
726 /* no siblings, go back through parents */
727 next = elem->next;
728 }
729 }
730 }
Michal Vasko4be5fa22017-02-07 10:12:32 +0100731}
Radek Krejci85a54be2016-10-20 12:39:56 +0200732
Michal Vasko4be5fa22017-02-07 10:12:32 +0100733static int
Radek Krejci83a4bac2017-02-07 15:53:04 +0100734ctx_modules_redo_backlinks(struct ly_set *mods)
Michal Vasko4be5fa22017-02-07 10:12:32 +0100735{
Radek Krejci83a4bac2017-02-07 15:53:04 +0100736 unsigned int i, j, k, s;
737 struct lys_module *mod;
738 struct lys_node *next, *elem;
739 struct lys_type *type;
740 struct lys_feature *feat;
Michal Vasko4be5fa22017-02-07 10:12:32 +0100741
Michal Vasko4be5fa22017-02-07 10:12:32 +0100742 for (i = 0; i < mods->number; ++i) {
Radek Krejci83a4bac2017-02-07 15:53:04 +0100743 mod = (struct lys_module *)mods->set.g[i]; /* shortcut */
Michal Vasko4be5fa22017-02-07 10:12:32 +0100744
Radek Krejci83a4bac2017-02-07 15:53:04 +0100745 /* identities */
746 for (j = 0; j < mod->ident_size; j++) {
747 for (k = 0; k < mod->ident[j].base_size; k++) {
748 resolve_identity_backlink_update(&mod->ident[j], mod->ident[j].base[k]);
749 }
750 }
Michal Vasko4be5fa22017-02-07 10:12:32 +0100751
Radek Krejci83a4bac2017-02-07 15:53:04 +0100752 /* features */
753 for (j = 0; j < mod->features_size; j++) {
754 for (k = 0; k < mod->features[j].iffeature_size; k++) {
755 resolve_iffeature_getsizes(&mod->features[j].iffeature[k], NULL, &s);
756 while (s--) {
757 feat = mod->features[j].iffeature[k].features[s]; /* shortcut */
758 if (!feat->depfeatures) {
759 feat->depfeatures = ly_set_new();
760 }
761 ly_set_add(feat->depfeatures, &mod->features[j], LY_SET_OPT_USEASLIST);
762 }
763 }
764 }
765
766 /* leafrefs */
767 LY_TREE_DFS_BEGIN(mod->data, next, elem) {
768 if (elem->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
769 type = &((struct lys_node_leaf *)elem)->type; /* shortcut */
770 if (type->base == LY_TYPE_LEAFREF) {
771 lys_leaf_add_leafref_target(type->info.lref.target, elem);
772 }
773 }
774
775 LY_TREE_DFS_END(mod->data, next, elem);
776 }
Michal Vasko4be5fa22017-02-07 10:12:32 +0100777 }
778
779 return 0;
Radek Krejci85a54be2016-10-20 12:39:56 +0200780}
781
Radek Krejci8c107fe2016-10-17 16:00:18 +0200782API int
Radek Krejci0ec51da2016-12-14 16:42:03 +0100783lys_set_disabled(const struct lys_module *module)
784{
785 struct ly_ctx *ctx; /* shortcut */
786 struct lys_module *mod;
787 struct ly_set *mods;
788 uint8_t j, imported;
789 int i, o;
790 unsigned int u;
791
792 if (!module) {
793 ly_errno = LY_EINVAL;
794 return EXIT_FAILURE;
795 } else if (module->disabled) {
796 /* already disabled module */
797 return EXIT_SUCCESS;
798 }
799 mod = (struct lys_module *)module;
800 ctx = mod->ctx;
801
802 /* avoid disabling internal modules */
803 for (i = 0; i < INTERNAL_MODULES_COUNT; i++) {
804 if (mod == ctx->models.list[i]) {
805 LOGERR(LY_EINVAL, "Internal module \"%s\" cannot be removed.", mod->name);
806 return EXIT_FAILURE;
807 }
808 }
809
810 /* disable the module */
811 mod->disabled = 1;
812
813 /* get the complete list of modules to disable because of dependencies,
814 * we are going also to disable all the imported (not implemented) modules
815 * that are not used in any other module */
816 mods = ly_set_new();
817 ly_set_add(mods, mod, 0);
818checkdependency:
819 for (i = INTERNAL_MODULES_COUNT; i < ctx->models.used; i++) {
820 mod = ctx->models.list[i]; /* shortcut */
821 if (mod->disabled) {
822 /* skip the already disabled modules */
823 continue;
824 }
825
826 /* check depndency of imported modules */
827 for (j = 0; j < mod->imp_size; j++) {
828 for (u = 0; u < mods->number; u++) {
829 if (mod->imp[j].module == mods->set.g[u]) {
830 /* module is importing some module to disable, so it must be also disabled */
831 mod->disabled = 1;
832 ly_set_add(mods, mod, 0);
833 /* we have to start again because some of the already checked modules can
834 * depend on the one we have just decided to disable */
835 goto checkdependency;
836 }
837 }
838 }
839 /* check if the imported module is used in any module supposed to be kept */
840 if (!mod->implemented) {
841 imported = 0;
842 for (o = INTERNAL_MODULES_COUNT; o < ctx->models.used; o++) {
843 if (ctx->models.list[o]->disabled) {
844 /* skip modules already disabled */
845 continue;
846 }
847 for (j = 0; j < ctx->models.list[o]->imp_size; j++) {
848 if (ctx->models.list[o]->imp[j].module == mod) {
849 /* the module is used in some other module not yet selected to be disabled */
850 imported = 1;
851 goto imported;
852 }
853 }
854 }
855imported:
856 if (!imported) {
857 /* module is not implemented and neither imported by any other module in context
858 * which is supposed to be kept enabled after this operation, so we are going to disable also
859 * this module */
860 mod->disabled = 1;
861 ly_set_add(mods, mod, 0);
862 /* we have to start again, this time not because other module can depend on this one
863 * (we know that there is no such module), but because the module can import module
864 * that could became useless. If there are no imports, we can continue */
865 if (mod->imp_size) {
866 goto checkdependency;
867 }
868 }
869 }
870 }
871
872 /* before removing applied deviations, augments and updating leafrefs, we have to enable the modules
873 * to disable to allow all that operations */
874 for (u = 0; u < mods->number; u++) {
875 ((struct lys_module *)mods->set.g[u])->disabled = 0;
876 }
877
878 /* maintain backlinks (start with internal ietf-yang-library which have leafs as possible targets of leafrefs */
Michal Vasko4be5fa22017-02-07 10:12:32 +0100879 ctx_modules_undo_backlinks(ctx, mods);
Radek Krejci0ec51da2016-12-14 16:42:03 +0100880
881 /* remove the applied deviations and augments */
882 for (u = 0; u < mods->number; u++) {
883 lys_sub_module_remove_devs_augs((struct lys_module *)mods->set.g[u]);
884 }
885
886 /* now again disable the modules to disable */
887 for (u = 0; u < mods->number; u++) {
888 ((struct lys_module *)mods->set.g[u])->disabled = 1;
889 }
890
891 /* free the set */
892 ly_set_free(mods);
893
894 /* update the module-set-id */
895 ctx->models.module_set_id++;
896
897 return EXIT_SUCCESS;
898}
899
900static void
901lys_set_enabled_(struct ly_set *mods, struct lys_module *mod)
902{
903 unsigned int i;
904
905 ly_set_add(mods, mod, 0);
906 mod->disabled = 0;
907
908 /* go recursively */
909 for (i = 0; i < mod->imp_size; i++) {
910 if (!mod->imp[i].module->disabled) {
911 continue;
912 }
913
914 lys_set_enabled_(mods, mod->imp[i].module);
915 }
916}
917
918API int
919lys_set_enabled(const struct lys_module *module)
920{
921 struct ly_ctx *ctx; /* shortcut */
922 struct lys_module *mod;
923 struct ly_set *mods, *disabled;
924 int i;
925 unsigned int u, v;
926
927 if (!module) {
928 ly_errno = LY_EINVAL;
929 return EXIT_FAILURE;
930 } else if (!module->disabled) {
931 /* already enabled module */
932 return EXIT_SUCCESS;
933 }
934 mod = (struct lys_module *)module;
935 ctx = mod->ctx;
936
937 /* avoid disabling internal modules */
938 for (i = 0; i < INTERNAL_MODULES_COUNT; i++) {
939 if (mod == ctx->models.list[i]) {
940 LOGERR(LY_EINVAL, "Internal module \"%s\" cannot be removed.", mod->name);
941 return EXIT_FAILURE;
942 }
943 }
944
945 mods = ly_set_new();
946 disabled = ly_set_new();
947
948 /* enable the module, including its dependencies */
949 lys_set_enabled_(mods, mod);
950
951 /* we will go through the all disabled modules in the context, if the module has no dependency (import)
952 * that is still disabled AND at least one of its imported module is from the set we are enabling now,
953 * it is going to be also enabled. This way we try to revert everething that was possibly done by
954 * lys_set_disabled(). */
955checkdependency:
956 for (i = INTERNAL_MODULES_COUNT; i < ctx->models.used; i++) {
957 mod = ctx->models.list[i]; /* shortcut */
958 if (!mod->disabled || ly_set_contains(disabled, mod) != -1) {
959 /* skip the enabled modules */
960 continue;
961 }
962
963 /* check imported modules */
964 for (u = 0; u < mod->imp_size; u++) {
965 if (mod->imp[u].module->disabled) {
966 /* it has disabled dependency so it must stay disabled */
967 break;
968 }
969 }
970 if (u < mod->imp_size) {
971 /* it has disabled dependency, continue with the next module in the context */
972 continue;
973 }
974
975 /* get know if at least one of the imported modules is being enabled this time */
976 for (u = 0; u < mod->imp_size; u++) {
977 for (v = 0; v < mods->number; v++) {
978 if (mod->imp[u].module == mods->set.g[v]) {
979 /* yes, it is, so they are connected and we are going to enable it as well,
980 * it is not necessary to call recursive lys_set_enable_() because we already
981 * know that there is no disabled import to enable */
982 mod->disabled = 0;
983 ly_set_add(mods, mod, 0);
984 /* we have to start again because some of the already checked modules can
985 * depend on the one we have just decided to enable */
986 goto checkdependency;
987 }
988 }
989 }
990
991 /* this module is disabled, but it does not depend on any other disabled module and none
992 * of its imports was not enabled in this call. No future enabling of the disabled module
993 * will change this so we can remember the module and skip it next time we will have to go
994 * through the all context because of the checkdependency goto.
995 */
996 ly_set_add(disabled, mod, 0);
997 }
998
999 /* maintain backlinks (start with internal ietf-yang-library which have leafs as possible targets of leafrefs */
Radek Krejci83a4bac2017-02-07 15:53:04 +01001000 ctx_modules_redo_backlinks(mods);
Radek Krejci0ec51da2016-12-14 16:42:03 +01001001
1002 /* re-apply the deviations and augments */
1003 for (v = 0; v < mods->number; v++) {
1004 lys_sub_module_apply_devs_augs((struct lys_module *)mods->set.g[v]);
1005 }
1006
1007 /* free the sets */
1008 ly_set_free(mods);
1009 ly_set_free(disabled);
1010
1011 /* update the module-set-id */
1012 ctx->models.module_set_id++;
1013
1014 return EXIT_SUCCESS;
1015}
1016
1017API int
1018ly_ctx_remove_module(const struct lys_module *module,
Radek Krejci8c107fe2016-10-17 16:00:18 +02001019 void (*private_destructor)(const struct lys_node *node, void *priv))
1020{
Radek Krejci0ec51da2016-12-14 16:42:03 +01001021 struct ly_ctx *ctx; /* shortcut */
Radek Krejci8c107fe2016-10-17 16:00:18 +02001022 struct lys_module *mod = NULL;
1023 struct ly_set *mods;
1024 uint8_t j, imported;
1025 int i, o;
1026 unsigned int u;
1027
Radek Krejci0ec51da2016-12-14 16:42:03 +01001028 if (!module) {
Radek Krejci8c107fe2016-10-17 16:00:18 +02001029 ly_errno = LY_EINVAL;
1030 return EXIT_FAILURE;
1031 }
1032
Radek Krejci0ec51da2016-12-14 16:42:03 +01001033 mod = (struct lys_module *)module;
1034 ctx = mod->ctx;
1035
Radek Krejci8c107fe2016-10-17 16:00:18 +02001036 /* avoid removing internal modules ... */
1037 for (i = 0; i < INTERNAL_MODULES_COUNT; i++) {
1038 if (mod == ctx->models.list[i]) {
Radek Krejci0ec51da2016-12-14 16:42:03 +01001039 LOGERR(LY_EINVAL, "Internal module \"%s\" cannot be removed.", mod->name);
Radek Krejci8c107fe2016-10-17 16:00:18 +02001040 return EXIT_FAILURE;
1041 }
1042 }
1043 /* ... and hide the module from the further processing of the context modules list */
1044 for (i = INTERNAL_MODULES_COUNT; i < ctx->models.used; i++) {
1045 if (mod == ctx->models.list[i]) {
1046 ctx->models.list[i] = NULL;
1047 break;
1048 }
1049 }
1050
1051 /* get the complete list of modules to remove because of dependencies,
1052 * we are going also to remove all the imported (not implemented) modules
1053 * that are not used in any other module */
1054 mods = ly_set_new();
1055 ly_set_add(mods, mod, 0);
1056checkdependency:
1057 for (i = INTERNAL_MODULES_COUNT; i < ctx->models.used; i++) {
1058 mod = ctx->models.list[i]; /* shortcut */
1059 if (!mod) {
1060 /* skip modules already selected for removing */
1061 continue;
1062 }
1063
1064 /* check depndency of imported modules */
1065 for (j = 0; j < mod->imp_size; j++) {
1066 for (u = 0; u < mods->number; u++) {
1067 if (mod->imp[j].module == mods->set.g[u]) {
1068 /* module is importing some module to remove, so it must be also removed */
1069 ly_set_add(mods, mod, 0);
1070 ctx->models.list[i] = NULL;
1071 /* we have to start again because some of the already checked modules can
1072 * depend on the one we have just decided to remove */
1073 goto checkdependency;
1074 }
1075 }
1076 }
1077 /* check if the imported module is used in any module supposed to be kept */
1078 if (!mod->implemented) {
1079 imported = 0;
1080 for (o = INTERNAL_MODULES_COUNT; o < ctx->models.used; o++) {
1081 if (!ctx->models.list[o]) {
1082 /* skip modules already selected for removing */
1083 continue;
1084 }
1085 for (j = 0; j < ctx->models.list[o]->imp_size; j++) {
1086 if (ctx->models.list[o]->imp[j].module == mod) {
1087 /* the module is used in some other module not yet selected to be deleted */
1088 imported = 1;
1089 goto imported;
1090 }
1091 }
1092 }
1093imported:
1094 if (!imported) {
1095 /* module is not implemented and neither imported by any other module in context
1096 * which is supposed to be kept after this operation, so we are going to remove also
1097 * this useless module */
1098 ly_set_add(mods, mod, 0);
1099 ctx->models.list[i] = NULL;
1100 /* we have to start again, this time not because other module can depend on this one
Radek Krejci0ec51da2016-12-14 16:42:03 +01001101 * (we know that there is no such module), but because the module can import module
Radek Krejci8c107fe2016-10-17 16:00:18 +02001102 * that could became useless. If there are no imports, we can continue */
1103 if (mod->imp_size) {
1104 goto checkdependency;
1105 }
1106 }
1107 }
1108 }
1109
Radek Krejci8c107fe2016-10-17 16:00:18 +02001110
1111 /* consolidate the modules list */
1112 for (i = o = INTERNAL_MODULES_COUNT; i < ctx->models.used; i++) {
1113 if (ctx->models.list[o]) {
1114 /* used cell */
1115 o++;
1116 } else {
1117 /* the current output cell is empty, move here an input cell */
1118 ctx->models.list[o] = ctx->models.list[i];
1119 ctx->models.list[i] = NULL;
1120 }
1121 }
1122 /* get the last used cell to get know the number of used */
1123 while (!ctx->models.list[o]) {
1124 o--;
1125 }
1126 ctx->models.used = o + 1;
1127 ctx->models.module_set_id++;
1128
Radek Krejci85a54be2016-10-20 12:39:56 +02001129 /* maintain backlinks (start with internal ietf-yang-library which have leafs as possible targets of leafrefs */
Michal Vasko4be5fa22017-02-07 10:12:32 +01001130 ctx_modules_undo_backlinks(ctx, mods);
Radek Krejci85a54be2016-10-20 12:39:56 +02001131
1132 /* free the modules */
1133 for (u = 0; u < mods->number; u++) {
Radek Krejcib2541a32016-12-12 16:45:57 +01001134 /* remove the applied deviations and augments */
1135 lys_sub_module_remove_devs_augs((struct lys_module *)mods->set.g[u]);
Radek Krejci85a54be2016-10-20 12:39:56 +02001136 /* remove the module */
1137 lys_free((struct lys_module *)mods->set.g[u], private_destructor, 0);
1138 }
1139 ly_set_free(mods);
1140
Radek Krejci8c107fe2016-10-17 16:00:18 +02001141 return EXIT_SUCCESS;
1142}
1143
Radek Krejci85a54be2016-10-20 12:39:56 +02001144API void
1145ly_ctx_clean(struct ly_ctx *ctx, void (*private_destructor)(const struct lys_node *node, void *priv))
1146{
Radek Krejci85a54be2016-10-20 12:39:56 +02001147 if (!ctx) {
1148 return;
1149 }
1150
1151 /* models list */
Radek Krejcic436a232017-02-08 14:43:11 +01001152 for (; ctx->models.used > INTERNAL_MODULES_COUNT; ctx->models.used--) {
Radek Krejcifc8411a2017-02-03 10:26:05 +01001153 /* remove the applied deviations and augments */
Radek Krejcic436a232017-02-08 14:43:11 +01001154 lys_sub_module_remove_devs_augs(ctx->models.list[ctx->models.used - 1]);
Radek Krejcifc8411a2017-02-03 10:26:05 +01001155 /* remove the module */
Radek Krejcic436a232017-02-08 14:43:11 +01001156 lys_free(ctx->models.list[ctx->models.used - 1], private_destructor, 0);
Radek Krejcifc8411a2017-02-03 10:26:05 +01001157 /* clean it for safer future use */
Radek Krejcic436a232017-02-08 14:43:11 +01001158 ctx->models.list[ctx->models.used - 1] = NULL;
Radek Krejci85a54be2016-10-20 12:39:56 +02001159 }
Radek Krejci85a54be2016-10-20 12:39:56 +02001160 ctx->models.module_set_id++;
1161
Radek Krejci83a4bac2017-02-07 15:53:04 +01001162 /* maintain backlinks (actually done only with ietf-yang-library since its leafs can be target of leafref) */
Michal Vasko4be5fa22017-02-07 10:12:32 +01001163 ctx_modules_undo_backlinks(ctx, NULL);
Radek Krejci85a54be2016-10-20 12:39:56 +02001164}
1165
Michal Vaskod7957c02016-04-01 10:27:26 +02001166API const struct lys_module *
1167ly_ctx_get_module_iter(const struct ly_ctx *ctx, uint32_t *idx)
1168{
1169 if (!ctx || !idx) {
1170 ly_errno = LY_EINVAL;
1171 return NULL;
1172 }
1173
Radek Krejci0ec51da2016-12-14 16:42:03 +01001174 for ( ; *idx < (unsigned)ctx->models.used; (*idx)++) {
1175 if (!ctx->models.list[(*idx)]->disabled) {
1176 return ctx->models.list[(*idx)++];
1177 }
1178 }
1179
1180 return NULL;
1181}
1182
1183API const struct lys_module *
1184ly_ctx_get_disabled_module_iter(const struct ly_ctx *ctx, uint32_t *idx)
1185{
1186 if (!ctx || !idx) {
1187 ly_errno = LY_EINVAL;
Michal Vaskod7957c02016-04-01 10:27:26 +02001188 return NULL;
1189 }
1190
Radek Krejci0ec51da2016-12-14 16:42:03 +01001191 for ( ; *idx < (unsigned)ctx->models.used; (*idx)++) {
1192 if (ctx->models.list[(*idx)]->disabled) {
1193 return ctx->models.list[(*idx)++];
1194 }
1195 }
1196
1197 return NULL;
Michal Vaskod7957c02016-04-01 10:27:26 +02001198}
1199
Michal Vasko209a6222015-10-16 09:51:07 +02001200static int
1201ylib_feature(struct lyd_node *parent, struct lys_module *cur_mod)
1202{
1203 int i, j;
1204
1205 /* module features */
1206 for (i = 0; i < cur_mod->features_size; ++i) {
1207 if (!(cur_mod->features[i].flags & LYS_FENABLED)) {
1208 continue;
1209 }
1210
Michal Vasko3e671b52015-10-23 16:23:15 +02001211 if (!lyd_new_leaf(parent, NULL, "feature", cur_mod->features[i].name)) {
Michal Vasko209a6222015-10-16 09:51:07 +02001212 return EXIT_FAILURE;
1213 }
1214 }
1215
1216 /* submodule features */
Radek Krejcic071c542016-01-27 14:57:51 +01001217 for (i = 0; i < cur_mod->inc_size && cur_mod->inc[i].submodule; ++i) {
Michal Vasko209a6222015-10-16 09:51:07 +02001218 for (j = 0; j < cur_mod->inc[i].submodule->features_size; ++j) {
1219 if (!(cur_mod->inc[i].submodule->features[j].flags & LYS_FENABLED)) {
1220 continue;
1221 }
1222
Michal Vasko3e671b52015-10-23 16:23:15 +02001223 if (!lyd_new_leaf(parent, NULL, "feature", cur_mod->inc[i].submodule->features[j].name)) {
Michal Vasko209a6222015-10-16 09:51:07 +02001224 return EXIT_FAILURE;
1225 }
1226 }
1227 }
1228
1229 return EXIT_SUCCESS;
1230}
1231
1232static int
Michal Vaskoff006c12016-02-17 11:15:19 +01001233ylib_deviation(struct lyd_node *parent, struct lys_module *cur_mod)
Michal Vasko97d8c6d2016-02-12 11:05:48 +01001234{
Michal Vasko89563fc2016-07-28 16:19:35 +02001235 uint32_t i = 0, j;
1236 const struct lys_module *mod;
Michal Vasko209a6222015-10-16 09:51:07 +02001237 struct lyd_node *cont;
Michal Vasko89563fc2016-07-28 16:19:35 +02001238 const char *ptr;
Michal Vasko209a6222015-10-16 09:51:07 +02001239
Michal Vasko89563fc2016-07-28 16:19:35 +02001240 if (cur_mod->deviated) {
1241 while ((mod = ly_ctx_get_module_iter(cur_mod->ctx, &i))) {
1242 if (mod == cur_mod) {
1243 continue;
Michal Vasko209a6222015-10-16 09:51:07 +02001244 }
Michal Vasko209a6222015-10-16 09:51:07 +02001245
Michal Vasko89563fc2016-07-28 16:19:35 +02001246 for (j = 0; j < mod->deviation_size; ++j) {
1247 ptr = strstr(mod->deviation[j].target_name, cur_mod->name);
1248 if (ptr && ptr[strlen(cur_mod->name)] == ':') {
1249 cont = lyd_new(parent, NULL, "deviation");
1250 if (!cont) {
1251 return EXIT_FAILURE;
1252 }
1253
1254 if (!lyd_new_leaf(cont, NULL, "name", mod->name)) {
1255 return EXIT_FAILURE;
1256 }
1257 if (!lyd_new_leaf(cont, NULL, "revision", (mod->rev_size ? mod->rev[0].date : ""))) {
1258 return EXIT_FAILURE;
1259 }
Michal Vasko0c2215b2016-08-25 14:18:43 +02001260
1261 break;
Michal Vasko89563fc2016-07-28 16:19:35 +02001262 }
Michal Vasko209a6222015-10-16 09:51:07 +02001263 }
1264 }
1265 }
1266
1267 return EXIT_SUCCESS;
1268}
1269
1270static int
1271ylib_submodules(struct lyd_node *parent, struct lys_module *cur_mod)
1272{
1273 int i;
Radek Krejcia77904e2016-02-25 16:23:45 +01001274 char *str;
Radek Krejcid9723912016-09-16 17:06:06 +02001275 struct lyd_node *item;
Michal Vasko209a6222015-10-16 09:51:07 +02001276
Radek Krejcic071c542016-01-27 14:57:51 +01001277 for (i = 0; i < cur_mod->inc_size && cur_mod->inc[i].submodule; ++i) {
Radek Krejcid9723912016-09-16 17:06:06 +02001278 item = lyd_new(parent, NULL, "submodule");
Radek Krejci6e05cea2015-12-10 16:34:37 +01001279 if (!item) {
Michal Vasko209a6222015-10-16 09:51:07 +02001280 return EXIT_FAILURE;
1281 }
1282
Radek Krejci6e05cea2015-12-10 16:34:37 +01001283 if (!lyd_new_leaf(item, NULL, "name", cur_mod->inc[i].submodule->name)) {
Michal Vasko209a6222015-10-16 09:51:07 +02001284 return EXIT_FAILURE;
1285 }
Radek Krejci6e05cea2015-12-10 16:34:37 +01001286 if (!lyd_new_leaf(item, NULL, "revision", (cur_mod->inc[i].submodule->rev_size ?
Michal Vasko3e671b52015-10-23 16:23:15 +02001287 cur_mod->inc[i].submodule->rev[0].date : ""))) {
Michal Vasko209a6222015-10-16 09:51:07 +02001288 return EXIT_FAILURE;
1289 }
Radek Krejcia77904e2016-02-25 16:23:45 +01001290 if (cur_mod->inc[i].submodule->filepath) {
Radek Krejci95aa2012016-03-03 11:21:09 +01001291 if (asprintf(&str, "file://%s", cur_mod->inc[i].submodule->filepath) == -1) {
Radek Krejcia77904e2016-02-25 16:23:45 +01001292 LOGMEM;
1293 return EXIT_FAILURE;
Radek Krejci6e65af92016-03-07 12:48:19 +01001294 } else if (!lyd_new_leaf(item, NULL, "schema", str)) {
Radek Krejci19f9ede2016-02-25 16:29:21 +01001295 free(str);
Radek Krejcia77904e2016-02-25 16:23:45 +01001296 return EXIT_FAILURE;
1297 }
Radek Krejci19f9ede2016-02-25 16:29:21 +01001298 free(str);
Michal Vasko209a6222015-10-16 09:51:07 +02001299 }
1300 }
1301
1302 return EXIT_SUCCESS;
1303}
1304
1305API struct lyd_node *
1306ly_ctx_info(struct ly_ctx *ctx)
1307{
1308 int i;
1309 char id[8];
Radek Krejcia77904e2016-02-25 16:23:45 +01001310 char *str;
Michal Vasko1e62a092015-12-01 12:27:20 +01001311 const struct lys_module *mod;
Michal Vasko209a6222015-10-16 09:51:07 +02001312 struct lyd_node *root, *cont;
1313
Michal Vasko7eccc6c2016-03-24 14:56:33 +01001314 if (!ctx) {
1315 ly_errno = LY_EINVAL;
1316 return NULL;
1317 }
1318
Radek Krejcibd9e8d22016-02-03 14:11:48 +01001319 mod = ly_ctx_get_module(ctx, "ietf-yang-library", IETF_YANG_LIB_REV);
1320 if (!mod || !mod->data) {
1321 LOGINT;
Michal Vasko209a6222015-10-16 09:51:07 +02001322 return NULL;
1323 }
1324
Radek Krejcibd9e8d22016-02-03 14:11:48 +01001325 root = lyd_new(NULL, mod, "modules-state");
Michal Vasko209a6222015-10-16 09:51:07 +02001326 if (!root) {
1327 return NULL;
1328 }
1329
1330 for (i = 0; i < ctx->models.used; ++i) {
Radek Krejci0ec51da2016-12-14 16:42:03 +01001331 if (ctx->models.list[i]->disabled) {
1332 /* skip the disabled modules */
1333 continue;
1334 }
1335
Michal Vasko209a6222015-10-16 09:51:07 +02001336 cont = lyd_new(root, NULL, "module");
1337 if (!cont) {
1338 lyd_free(root);
1339 return NULL;
1340 }
1341
Michal Vasko3e671b52015-10-23 16:23:15 +02001342 if (!lyd_new_leaf(cont, NULL, "name", ctx->models.list[i]->name)) {
Michal Vasko209a6222015-10-16 09:51:07 +02001343 lyd_free(root);
1344 return NULL;
1345 }
Michal Vasko3e671b52015-10-23 16:23:15 +02001346 if (!lyd_new_leaf(cont, NULL, "revision", (ctx->models.list[i]->rev_size ?
Michal Vasko209a6222015-10-16 09:51:07 +02001347 ctx->models.list[i]->rev[0].date : ""))) {
1348 lyd_free(root);
1349 return NULL;
1350 }
Radek Krejcia77904e2016-02-25 16:23:45 +01001351 if (ctx->models.list[i]->filepath) {
Radek Krejci15412ca2016-03-03 11:16:52 +01001352 if (asprintf(&str, "file://%s", ctx->models.list[i]->filepath) == -1) {
Radek Krejcia77904e2016-02-25 16:23:45 +01001353 LOGMEM;
1354 lyd_free(root);
1355 return NULL;
1356 } else if (!lyd_new_leaf(cont, NULL, "schema", str)) {
Radek Krejci19f9ede2016-02-25 16:29:21 +01001357 free(str);
Radek Krejcia77904e2016-02-25 16:23:45 +01001358 lyd_free(root);
1359 return NULL;
1360 }
Radek Krejci19f9ede2016-02-25 16:29:21 +01001361 free(str);
Michal Vasko209a6222015-10-16 09:51:07 +02001362 }
Michal Vasko3e671b52015-10-23 16:23:15 +02001363 if (!lyd_new_leaf(cont, NULL, "namespace", ctx->models.list[i]->ns)) {
Michal Vasko209a6222015-10-16 09:51:07 +02001364 lyd_free(root);
1365 return NULL;
1366 }
1367 if (ylib_feature(cont, ctx->models.list[i])) {
1368 lyd_free(root);
1369 return NULL;
1370 }
Michal Vaskoff006c12016-02-17 11:15:19 +01001371 if (ylib_deviation(cont, ctx->models.list[i])) {
Michal Vasko209a6222015-10-16 09:51:07 +02001372 lyd_free(root);
1373 return NULL;
1374 }
1375 if (ctx->models.list[i]->implemented
Radek Krejcibd9e8d22016-02-03 14:11:48 +01001376 && !lyd_new_leaf(cont, NULL, "conformance-type", "implement")) {
Michal Vasko209a6222015-10-16 09:51:07 +02001377 lyd_free(root);
1378 return NULL;
1379 }
1380 if (!ctx->models.list[i]->implemented
Radek Krejcibd9e8d22016-02-03 14:11:48 +01001381 && !lyd_new_leaf(cont, NULL, "conformance-type", "import")) {
Michal Vasko209a6222015-10-16 09:51:07 +02001382 lyd_free(root);
1383 return NULL;
1384 }
1385 if (ylib_submodules(cont, ctx->models.list[i])) {
1386 lyd_free(root);
1387 return NULL;
1388 }
1389 }
1390
1391 sprintf(id, "%u", ctx->models.module_set_id);
Michal Vasko3e671b52015-10-23 16:23:15 +02001392 if (!lyd_new_leaf(root, mod, "module-set-id", id)) {
Michal Vasko209a6222015-10-16 09:51:07 +02001393 lyd_free(root);
1394 return NULL;
1395 }
1396
Michal Vaskocdb90172016-09-13 09:34:36 +02001397 if (lyd_validate(&root, LYD_OPT_NOSIBLINGS, NULL)) {
Michal Vasko209a6222015-10-16 09:51:07 +02001398 lyd_free(root);
1399 return NULL;
1400 }
1401
1402 return root;
1403}
Michal Vasko3edeaf72016-02-11 13:17:43 +01001404
1405API const struct lys_node *
Michal Vasko3547c532016-03-14 09:40:50 +01001406ly_ctx_get_node(struct ly_ctx *ctx, const struct lys_node *start, const char *nodeid)
Michal Vasko3edeaf72016-02-11 13:17:43 +01001407{
Michal Vaskoe733d682016-03-14 09:08:27 +01001408 const struct lys_node *node;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001409
Michal Vasko3547c532016-03-14 09:40:50 +01001410 if (!ctx || !nodeid || ((nodeid[0] != '/') && !start)) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001411 ly_errno = LY_EINVAL;
1412 return NULL;
1413 }
1414
Michal Vaskoe733d682016-03-14 09:08:27 +01001415 /* sets error and everything */
Michal Vasko8d26e5c2016-09-08 10:03:49 +02001416 node = resolve_json_nodeid(nodeid, ctx, start);
Michal Vasko3edeaf72016-02-11 13:17:43 +01001417
Michal Vaskoe733d682016-03-14 09:08:27 +01001418 return node;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001419}