blob: a0f64398fe8c220637ec55e061abe51464572692 [file] [log] [blame]
Radek Krejcida04f4a2015-05-21 12:54:09 +02001/**
2 * @file context.c
3 * @author Radek Krejci <rkrejci@cesnet.cz>
4 * @brief context implementation for libyang
5 *
6 * Copyright (c) 2015 CESNET, z.s.p.o.
7 *
Radek Krejci54f6fb32016-02-24 12:56:39 +01008 * This source code is licensed under BSD 3-Clause License (the "License").
9 * You may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
Michal Vasko8de098c2016-02-26 10:00:25 +010011 *
Radek Krejci54f6fb32016-02-24 12:56:39 +010012 * https://opensource.org/licenses/BSD-3-Clause
Radek Krejcida04f4a2015-05-21 12:54:09 +020013 */
14
15#define _GNU_SOURCE
Radek Krejcicf748252017-09-04 11:11:14 +020016#include <pthread.h>
Radek Krejcifd4e6e32015-08-10 15:00:51 +020017#include <stddef.h>
Radek Krejcida04f4a2015-05-21 12:54:09 +020018#include <stdlib.h>
19#include <string.h>
20#include <sys/types.h>
21#include <sys/stat.h>
22#include <unistd.h>
23#include <errno.h>
24#include <fcntl.h>
25
26#include "common.h"
27#include "context.h"
Radek Krejci41912fe2015-10-22 10:22:12 +020028#include "dict_private.h"
Michal Vasko209a6222015-10-16 09:51:07 +020029#include "parser.h"
Radek Krejcibc9cf932015-07-30 11:09:39 +020030#include "tree_internal.h"
Radek Krejci83a4bac2017-02-07 15:53:04 +010031#include "resolve.h"
Radek Krejcida04f4a2015-05-21 12:54:09 +020032
Radek Krejci858ad952017-01-04 11:16:32 +010033/*
34 * counter for references to the extensions plugins (for the number of contexts)
35 * located in extensions.c
36 */
37extern unsigned int ext_plugins_ref;
38
Radek Krejci532e5e92017-02-22 12:59:24 +010039#define IETF_YANG_METADATA_PATH "../models/ietf-yang-metadata@2016-08-05.h"
40#define YANG_PATH "../models/yang@2017-02-20.h"
Michal Vasko8d054e42015-08-03 12:42:06 +020041#define IETF_INET_TYPES_PATH "../models/ietf-inet-types@2013-07-15.h"
Michal Vasko21181c42015-08-03 13:46:45 +020042#define IETF_YANG_TYPES_PATH "../models/ietf-yang-types@2013-07-15.h"
Radek Krejcidfb00d62017-09-06 09:39:35 +020043#define IETF_DATASTORES "../models/ietf-datastores@2017-08-17.h"
44#define IETF_YANG_LIB_PATH "../models/ietf-yang-library@2017-08-17.h"
45#define IETF_YANG_LIB_REV "2017-08-17"
Michal Vasko8d054e42015-08-03 12:42:06 +020046
Radek Krejci532e5e92017-02-22 12:59:24 +010047#include IETF_YANG_METADATA_PATH
48#include YANG_PATH
Michal Vasko8d054e42015-08-03 12:42:06 +020049#include IETF_INET_TYPES_PATH
Michal Vasko21181c42015-08-03 13:46:45 +020050#include IETF_YANG_TYPES_PATH
Radek Krejcidfb00d62017-09-06 09:39:35 +020051#include IETF_DATASTORES
Michal Vasko8d054e42015-08-03 12:42:06 +020052#include IETF_YANG_LIB_PATH
53
Radek Krejcidfb00d62017-09-06 09:39:35 +020054#define LY_INTERNAL_MODULE_COUNT 6
Radek Krejci03203412016-06-23 15:20:53 +020055static struct internal_modules_s {
56 const char *name;
57 const char *revision;
58 const char *data;
59 uint8_t implemented;
60 LYS_INFORMAT format;
Michal Vasko2d051a12017-04-21 09:28:57 +020061} internal_modules[LY_INTERNAL_MODULE_COUNT] = {
Radek Krejci532e5e92017-02-22 12:59:24 +010062 {"ietf-yang-metadata", "2016-08-05", (const char*)ietf_yang_metadata_2016_08_05_yin, 0, LYS_IN_YIN},
63 {"yang", "2017-02-20", (const char*)yang_2017_02_20_yin, 1, LYS_IN_YIN},
Radek Krejci03203412016-06-23 15:20:53 +020064 {"ietf-inet-types", "2013-07-15", (const char*)ietf_inet_types_2013_07_15_yin, 0, LYS_IN_YIN},
65 {"ietf-yang-types", "2013-07-15", (const char*)ietf_yang_types_2013_07_15_yin, 0, LYS_IN_YIN},
Radek Krejcidfb00d62017-09-06 09:39:35 +020066 /* ietf-datastores and ietf-yang-library must be right here at the end of the list! */
67 {"ietf-datastores", "2017-08-17", (const char*)ietf_datastores_2017_08_17_yin, 0, LYS_IN_YIN},
68 {"ietf-yang-library", IETF_YANG_LIB_REV, (const char*)ietf_yang_library_2017_08_17_yin, 1, LYS_IN_YIN}
Radek Krejci03203412016-06-23 15:20:53 +020069};
70
Radek Krejcidfb00d62017-09-06 09:39:35 +020071API unsigned int
72ly_ctx_internal_modules_count(struct ly_ctx *ctx)
73{
74 if (!ctx) {
75 return 0;
76 }
77 return ctx->internal_module_count;
78}
79
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020080API struct ly_ctx *
Radek Krejcidd3263a2017-07-15 11:50:09 +020081ly_ctx_new(const char *search_dir, int options)
Radek Krejcida04f4a2015-05-21 12:54:09 +020082{
Radek Krejcia8d111f2017-05-31 13:57:37 +020083 struct ly_ctx *ctx = NULL;
Michal Vasko7d7de952016-05-02 17:13:14 +020084 struct lys_module *module;
Radek Krejcia8d111f2017-05-31 13:57:37 +020085 char *cwd = NULL;
Igor Ternovsky9a10e1a2017-09-11 12:53:04 +100086 char *search_dir_list;
87 char *sep, *dir;
Igor Ternovsky6e6543d2017-09-12 10:37:28 +100088 int rc = EXIT_SUCCESS;
Radek Krejci03203412016-06-23 15:20:53 +020089 int i;
Radek Krejcida04f4a2015-05-21 12:54:09 +020090
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020091 ctx = calloc(1, sizeof *ctx);
Radek Krejcia8d111f2017-05-31 13:57:37 +020092 LY_CHECK_ERR_RETURN(!ctx, LOGMEM, NULL);
Radek Krejcida04f4a2015-05-21 12:54:09 +020093
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020094 /* dictionary */
95 lydict_init(&ctx->dict);
Radek Krejcida04f4a2015-05-21 12:54:09 +020096
Radek Krejci858ad952017-01-04 11:16:32 +010097 /* plugins */
Radek Krejci858ad952017-01-04 11:16:32 +010098 lyext_load_plugins();
99
Radek Krejcicf748252017-09-04 11:11:14 +0200100 /* initialize thread-specific key */
101 while ((i = pthread_key_create(&ctx->errlist_key, ly_err_free)) == EAGAIN);
102
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200103 /* models list */
104 ctx->models.list = calloc(16, sizeof *ctx->models.list);
Radek Krejcia8d111f2017-05-31 13:57:37 +0200105 LY_CHECK_ERR_RETURN(!ctx->models.list, LOGMEM; free(ctx), NULL);
Radek Krejci37d02632017-02-21 14:14:11 +0100106 ext_plugins_ref++;
Radek Krejcidd3263a2017-07-15 11:50:09 +0200107 ctx->models.flags = options;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200108 ctx->models.used = 0;
109 ctx->models.size = 16;
110 if (search_dir) {
Igor Ternovsky9a10e1a2017-09-11 12:53:04 +1000111 search_dir_list = strdup(search_dir);
112 LY_CHECK_ERR_GOTO(!search_dir_list, LOGMEM, error);
113
Igor Ternovsky6e6543d2017-09-12 10:37:28 +1000114 for (dir = search_dir_list; (sep = strchr(dir, ':')) != NULL && rc == EXIT_SUCCESS; dir = sep + 1) {
Igor Ternovsky9a10e1a2017-09-11 12:53:04 +1000115 *sep = 0;
Igor Ternovsky6e6543d2017-09-12 10:37:28 +1000116 rc = ly_ctx_set_searchdir(ctx, dir);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200117 }
Igor Ternovsky6e6543d2017-09-12 10:37:28 +1000118 if (*dir && rc == EXIT_SUCCESS) {
119 rc = ly_ctx_set_searchdir(ctx, dir);
Radek Krejci15412ca2016-03-03 11:16:52 +0100120 }
Igor Ternovsky9a10e1a2017-09-11 12:53:04 +1000121 free(search_dir_list);
Igor Ternovsky6e6543d2017-09-12 10:37:28 +1000122 /* If ly_ctx_set_searchdir() failed, the error is already logged. Just exit */
123 if (rc != EXIT_SUCCESS) {
124 goto error;
125 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200126 }
Michal Vasko14719b22015-08-03 12:47:55 +0200127 ctx->models.module_set_id = 1;
128
Radek Krejci03203412016-06-23 15:20:53 +0200129 /* load internal modules */
Radek Krejcidfb00d62017-09-06 09:39:35 +0200130 if (options & LY_CTX_NOYANGLIBRARY) {
131 ctx->internal_module_count = LY_INTERNAL_MODULE_COUNT - 2;
132 } else {
133 ctx->internal_module_count = LY_INTERNAL_MODULE_COUNT;
134 }
135 for (i = 0; i < ctx->internal_module_count; i++) {
Radek Krejci03203412016-06-23 15:20:53 +0200136 module = (struct lys_module *)lys_parse_mem(ctx, internal_modules[i].data, internal_modules[i].format);
137 if (!module) {
Radek Krejcia8d111f2017-05-31 13:57:37 +0200138 goto error;
Radek Krejci03203412016-06-23 15:20:53 +0200139 }
140 module->implemented = internal_modules[i].implemented;
Michal Vasko8d054e42015-08-03 12:42:06 +0200141 }
Radek Krejcida04f4a2015-05-21 12:54:09 +0200142
Radek Krejcia8d111f2017-05-31 13:57:37 +0200143 /* cleanup */
144 free(cwd);
145
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200146 return ctx;
Radek Krejcia8d111f2017-05-31 13:57:37 +0200147
148error:
149 free(cwd);
150 ly_ctx_destroy(ctx, NULL);
151 return NULL;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200152}
153
Radek Krejci69333c92017-03-17 16:14:43 +0100154static struct ly_ctx *
Radek Krejcidd3263a2017-07-15 11:50:09 +0200155ly_ctx_new_yl_common(const char *search_dir, const char *input, LYD_FORMAT format, int options,
Radek Krejci69333c92017-03-17 16:14:43 +0100156 struct lyd_node* (*parser_func)(struct ly_ctx*, const char*, LYD_FORMAT, int,...))
157{
158 unsigned int u;
159 struct lyd_node *module, *node;
160 const char *name, *revision;
Radek Krejci5cb217d2017-03-25 16:07:52 -0500161 struct ly_set features = {0, 0, {NULL}};
Radek Krejci69333c92017-03-17 16:14:43 +0100162 const struct lys_module *mod;
163 struct lyd_node *yltree = NULL;
164 struct ly_ctx *ctx = NULL;
165
166 /* create empty (with internal modules including ietf-yang-library) context */
Radek Krejcidd3263a2017-07-15 11:50:09 +0200167 ctx = ly_ctx_new(search_dir, options);
Radek Krejci69333c92017-03-17 16:14:43 +0100168 if (!ctx) {
169 goto error;
170 }
171
172 /* parse yang library data tree */
173 yltree = parser_func(ctx, input, format, LYD_OPT_DATA, NULL);
174 if (!yltree) {
175 goto error;
176 }
177
178 /* process the data tree */
179 LY_TREE_FOR(yltree->child, module) {
180 if (module->schema->nodetype == LYS_LEAF) {
181 /* module-set-id - ignore it */
182 continue;
183 }
184
185 /* initiate */
186 name = NULL;
187 revision = NULL;
188 ly_set_clean(&features);
189
190 LY_TREE_FOR(module->child, node) {
191 if (!strcmp(node->schema->name, "name")) {
192 name = ((struct lyd_node_leaf_list*)node)->value_str;
193 } else if (!strcmp(node->schema->name, "revision")) {
194 revision = ((struct lyd_node_leaf_list*)node)->value_str;
195 } else if (!strcmp(node->schema->name, "feature")) {
196 ly_set_add(&features, node, LY_SET_OPT_USEASLIST);
197 } else if (!strcmp(node->schema->name, "conformance-type") &&
198 ((struct lyd_node_leaf_list*)node)->value.enm->value) {
199 /* imported module - skip it, it will be loaded as a side effect
200 * of loading another module */
201 goto next_module;
202 }
203 }
204
205 /* use the gathered data to load the module */
206 mod = ly_ctx_load_module(ctx, name, revision);
207 if (!mod) {
208 LOGERR(LY_EINVAL, "Unable to load module specified by yang library data.");
209 goto error;
210 }
211
212 /* set features */
213 for (u = 0; u < features.number; u++) {
214 lys_features_enable(mod, ((struct lyd_node_leaf_list*)features.set.d[u])->value_str);
215 }
216
217next_module:;
218 }
219
220 if (0) {
221 /* skip context destroy in case of success */
222error:
223 ly_ctx_destroy(ctx, NULL);
224 ctx = NULL;
225 }
226
227 /* cleanup */
228 if (yltree) {
229 /* yang library data tree */
230 lyd_free_withsiblings(yltree);
231 }
232
233 return ctx;
234}
235
236API struct ly_ctx *
Radek Krejcidd3263a2017-07-15 11:50:09 +0200237ly_ctx_new_ylpath(const char *search_dir, const char *path, LYD_FORMAT format, int options)
Radek Krejci69333c92017-03-17 16:14:43 +0100238{
Radek Krejcidd3263a2017-07-15 11:50:09 +0200239 return ly_ctx_new_yl_common(search_dir, path, format, options, lyd_parse_path);
Radek Krejci69333c92017-03-17 16:14:43 +0100240}
241
242API struct ly_ctx *
Radek Krejcidd3263a2017-07-15 11:50:09 +0200243ly_ctx_new_ylmem(const char *search_dir, const char *data, LYD_FORMAT format, int options)
Radek Krejci69333c92017-03-17 16:14:43 +0100244{
Radek Krejcidd3263a2017-07-15 11:50:09 +0200245 return ly_ctx_new_yl_common(search_dir, data, format, options, lyd_parse_mem);
246}
247
248static void
249ly_ctx_set_option(struct ly_ctx *ctx, int options)
250{
251 if (!ctx) {
252 return;
253 }
254
255 ctx->models.flags |= options;
256}
257
258static void
259ly_ctx_unset_option(struct ly_ctx *ctx, int options)
260{
261 if (!ctx) {
262 return;
263 }
264
265 ctx->models.flags &= ~options;
Radek Krejci69333c92017-03-17 16:14:43 +0100266}
267
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200268API void
Radek Krejci819dd4b2017-03-07 15:35:48 +0100269ly_ctx_set_allimplemented(struct ly_ctx *ctx)
270{
Radek Krejcidd3263a2017-07-15 11:50:09 +0200271 ly_ctx_set_option(ctx, LY_CTX_ALLIMPLEMENTED);
Radek Krejci819dd4b2017-03-07 15:35:48 +0100272}
273
274API void
275ly_ctx_unset_allimplemented(struct ly_ctx *ctx)
276{
Radek Krejcidd3263a2017-07-15 11:50:09 +0200277 ly_ctx_unset_option(ctx, LY_CTX_ALLIMPLEMENTED);
278}
Radek Krejci819dd4b2017-03-07 15:35:48 +0100279
Radek Krejcidd3263a2017-07-15 11:50:09 +0200280API void
281ly_ctx_set_trusted(struct ly_ctx *ctx)
282{
283 ly_ctx_set_option(ctx, LY_CTX_TRUSTED);
284}
285
286API void
287ly_ctx_unset_trusted(struct ly_ctx *ctx)
288{
289 ly_ctx_unset_option(ctx, LY_CTX_TRUSTED);
Radek Krejci819dd4b2017-03-07 15:35:48 +0100290}
291
Igor Ternovsky6e6543d2017-09-12 10:37:28 +1000292API int
Michal Vasko60ba9a62015-07-03 14:42:31 +0200293ly_ctx_set_searchdir(struct ly_ctx *ctx, const char *search_dir)
294{
Radek Krejcia62a9d12017-08-09 12:37:51 +0200295 char *cwd = NULL, *new = NULL;
Radek Krejcida9f8392017-03-25 19:40:56 -0500296 int index = 0;
297 void *r;
Igor Ternovsky6e6543d2017-09-12 10:37:28 +1000298 int rc = EXIT_FAILURE;
Michal Vasko60ba9a62015-07-03 14:42:31 +0200299
300 if (!ctx) {
Radek Krejci961d96f2017-09-12 10:31:17 +0200301 LOGERR(LY_EINVAL, "%s: Invalid ctx parameter", __func__);
Igor Ternovsky6e6543d2017-09-12 10:37:28 +1000302 return EXIT_FAILURE;
Michal Vasko60ba9a62015-07-03 14:42:31 +0200303 }
304
305 if (search_dir) {
306 cwd = get_current_dir_name();
307 if (chdir(search_dir)) {
308 LOGERR(LY_ESYS, "Unable to use search directory \"%s\" (%s)",
309 search_dir, strerror(errno));
Radek Krejcia8d111f2017-05-31 13:57:37 +0200310 goto cleanup;
Michal Vasko60ba9a62015-07-03 14:42:31 +0200311 }
Radek Krejcida9f8392017-03-25 19:40:56 -0500312
Radek Krejci426ea2b2017-06-13 12:41:51 +0200313 new = get_current_dir_name();
Radek Krejcida9f8392017-03-25 19:40:56 -0500314 if (!ctx->models.search_paths) {
315 ctx->models.search_paths = malloc(2 * sizeof *ctx->models.search_paths);
Radek Krejcia8d111f2017-05-31 13:57:37 +0200316 LY_CHECK_ERR_GOTO(!ctx->models.search_paths, LOGMEM, cleanup);
Radek Krejcida9f8392017-03-25 19:40:56 -0500317 index = 0;
318 } else {
Radek Krejci426ea2b2017-06-13 12:41:51 +0200319 for (index = 0; ctx->models.search_paths[index]; index++) {
320 /* check for duplicities */
321 if (!strcmp(new, ctx->models.search_paths[index])) {
322 /* path is already present */
Radek Krejci426ea2b2017-06-13 12:41:51 +0200323 goto success;
324 }
325 }
Radek Krejcida9f8392017-03-25 19:40:56 -0500326 r = realloc(ctx->models.search_paths, (index + 2) * sizeof *ctx->models.search_paths);
Radek Krejcia8d111f2017-05-31 13:57:37 +0200327 LY_CHECK_ERR_GOTO(!r, LOGMEM, cleanup);
Radek Krejcida9f8392017-03-25 19:40:56 -0500328 ctx->models.search_paths = r;
329 }
Radek Krejci426ea2b2017-06-13 12:41:51 +0200330 ctx->models.search_paths[index] = new;
Radek Krejcia62a9d12017-08-09 12:37:51 +0200331 new = NULL;
Radek Krejcida9f8392017-03-25 19:40:56 -0500332 ctx->models.search_paths[index + 1] = NULL;
Michal Vasko3eff9322015-11-10 11:02:30 +0100333
Radek Krejci426ea2b2017-06-13 12:41:51 +0200334success:
Radek Krejci15412ca2016-03-03 11:16:52 +0100335 if (chdir(cwd)) {
336 LOGWRN("Unable to return back to working directory \"%s\" (%s)",
337 cwd, strerror(errno));
338 }
Igor Ternovsky6e6543d2017-09-12 10:37:28 +1000339 rc = EXIT_SUCCESS;
Radek Krejci9287c702017-09-12 10:32:24 +0200340 } else {
341 /* consider that no change is not actually an error */
342 return EXIT_SUCCESS;
Michal Vasko60ba9a62015-07-03 14:42:31 +0200343 }
Radek Krejcia8d111f2017-05-31 13:57:37 +0200344
345cleanup:
346 free(cwd);
Radek Krejcia62a9d12017-08-09 12:37:51 +0200347 free(new);
Igor Ternovsky6e6543d2017-09-12 10:37:28 +1000348 return rc;
Michal Vasko60ba9a62015-07-03 14:42:31 +0200349}
350
Radek Krejci426ea2b2017-06-13 12:41:51 +0200351API const char * const *
352ly_ctx_get_searchdirs(const struct ly_ctx *ctx)
Radek Krejci5a797572015-10-21 15:45:45 +0200353{
Radek Krejciee554172016-12-14 10:29:06 +0100354 if (!ctx) {
Radek Krejci961d96f2017-09-12 10:31:17 +0200355 LOGERR(LY_EINVAL, "%s: Invalid ctx parameter", __func__);
Radek Krejciee554172016-12-14 10:29:06 +0100356 return NULL;
357 }
Radek Krejci426ea2b2017-06-13 12:41:51 +0200358 return (const char * const *)ctx->models.search_paths;
Radek Krejcida9f8392017-03-25 19:40:56 -0500359}
360
361API void
Radek Krejcidb4e9ff2017-06-13 16:26:14 +0200362ly_ctx_unset_searchdirs(struct ly_ctx *ctx, int index)
Radek Krejcida9f8392017-03-25 19:40:56 -0500363{
364 int i;
365
366 if (!ctx->models.search_paths) {
367 return;
368 }
369
370 for (i = 0; ctx->models.search_paths[i]; i++) {
Radek Krejcidb4e9ff2017-06-13 16:26:14 +0200371 if (index < 0 || index == i) {
372 free(ctx->models.search_paths[i]);
373 ctx->models.search_paths[i] = NULL;
374 } else if (i > index) {
375 ctx->models.search_paths[i - 1] = ctx->models.search_paths[i];
376 ctx->models.search_paths[i] = NULL;
377 }
Radek Krejcida9f8392017-03-25 19:40:56 -0500378 }
Radek Krejcidb4e9ff2017-06-13 16:26:14 +0200379 if (index < 0 || !ctx->models.search_paths[0]) {
380 free(ctx->models.search_paths);
381 ctx->models.search_paths = NULL;
382 }
Radek Krejci5a797572015-10-21 15:45:45 +0200383}
384
Michal Vasko60ba9a62015-07-03 14:42:31 +0200385API void
Radek Krejcifa0b5e02016-02-04 13:57:03 +0100386ly_ctx_destroy(struct ly_ctx *ctx, void (*private_destructor)(const struct lys_node *node, void *priv))
Radek Krejcida04f4a2015-05-21 12:54:09 +0200387{
Radek Krejcida9f8392017-03-25 19:40:56 -0500388 int i;
389
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200390 if (!ctx) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200391 return;
392 }
Radek Krejcida04f4a2015-05-21 12:54:09 +0200393
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200394 /* models list */
Radek Krejcic436a232017-02-08 14:43:11 +0100395 for (; ctx->models.used > 0; ctx->models.used--) {
Radek Krejcifc8411a2017-02-03 10:26:05 +0100396 /* remove the applied deviations and augments */
Radek Krejcic436a232017-02-08 14:43:11 +0100397 lys_sub_module_remove_devs_augs(ctx->models.list[ctx->models.used - 1]);
Radek Krejcifc8411a2017-02-03 10:26:05 +0100398 /* remove the module */
Radek Krejcic436a232017-02-08 14:43:11 +0100399 lys_free(ctx->models.list[ctx->models.used - 1], private_destructor, 0);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200400 }
Radek Krejcida9f8392017-03-25 19:40:56 -0500401 if (ctx->models.search_paths) {
402 for(i = 0; ctx->models.search_paths[i]; i++) {
403 free(ctx->models.search_paths[i]);
404 }
405 free(ctx->models.search_paths);
406 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200407 free(ctx->models.list);
Radek Krejcida04f4a2015-05-21 12:54:09 +0200408
Radek Krejcicf748252017-09-04 11:11:14 +0200409 /* clean the error list */
410 ly_err_clean(ctx, 0);
411 pthread_key_delete(ctx->errlist_key);
412
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200413 /* dictionary */
414 lydict_clean(&ctx->dict);
Radek Krejcida04f4a2015-05-21 12:54:09 +0200415
Radek Krejci858ad952017-01-04 11:16:32 +0100416 /* plugins - will be removed only if this is the last context */
417 ext_plugins_ref--;
418 lyext_clean_plugins();
419
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200420 free(ctx);
Radek Krejcida04f4a2015-05-21 12:54:09 +0200421}
422
Michal Vasko1e62a092015-12-01 12:27:20 +0100423API const struct lys_submodule *
Radek Krejci62f0da72016-03-07 11:35:43 +0100424ly_ctx_get_submodule2(const struct lys_module *main_module, const char *submodule)
425{
Radek Krejcid4c1d0f2017-01-19 16:11:38 +0100426 const struct lys_submodule *result;
Radek Krejci62f0da72016-03-07 11:35:43 +0100427 int i;
428
429 if (!main_module || !submodule) {
430 ly_errno = LY_EINVAL;
431 return NULL;
432 }
433
434 /* search in submodules list */
435 for (i = 0; i < main_module->inc_size; i++) {
436 result = main_module->inc[i].submodule;
Radek Krejcid4c1d0f2017-01-19 16:11:38 +0100437 if (ly_strequal(submodule, result->name, 0)) {
Radek Krejci62f0da72016-03-07 11:35:43 +0100438 return result;
439 }
Radek Krejcid4c1d0f2017-01-19 16:11:38 +0100440
441 /* in YANG 1.1 all the submodules must be included in the main module, so we are done.
442 * YANG 1.0 allows (is unclear about denying it) to include a submodule only in another submodule
443 * but when libyang parses such a module it adds the include into the main module so we are also done.
444 */
Radek Krejci62f0da72016-03-07 11:35:43 +0100445 }
446
Radek Krejcid4c1d0f2017-01-19 16:11:38 +0100447
Radek Krejci62f0da72016-03-07 11:35:43 +0100448 return NULL;
449}
450
451API const struct lys_submodule *
Michal Vaskof6d94c62016-04-05 11:21:54 +0200452ly_ctx_get_submodule(const struct ly_ctx *ctx, const char *module, const char *revision, const char *submodule,
453 const char *sub_revision)
Radek Krejciefaeba32015-05-27 14:30:57 +0200454{
Radek Krejcie7973552016-03-07 08:12:01 +0100455 const struct lys_module *mainmod;
Michal Vaskof6d94c62016-04-05 11:21:54 +0200456 const struct lys_submodule *ret = NULL, *submod;
457 uint32_t idx = 0;
Radek Krejciefaeba32015-05-27 14:30:57 +0200458
Michal Vaskof6d94c62016-04-05 11:21:54 +0200459 if (!ctx || !submodule || (revision && !module)) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200460 ly_errno = LY_EINVAL;
461 return NULL;
462 }
Radek Krejciefaeba32015-05-27 14:30:57 +0200463
Michal Vaskof6d94c62016-04-05 11:21:54 +0200464 while ((mainmod = ly_ctx_get_module_iter(ctx, &idx))) {
465 if (module && strcmp(mainmod->name, module)) {
466 /* main module name does not match */
467 continue;
468 }
469
470 if (revision && (!mainmod->rev || strcmp(revision, mainmod->rev[0].date))) {
471 /* main module revision does not match */
472 continue;
473 }
474
475 submod = ly_ctx_get_submodule2(mainmod, submodule);
476 if (!submod) {
477 continue;
478 }
479
480 if (!sub_revision) {
481 /* store only if newer */
482 if (ret) {
483 if (submod->rev && (!ret->rev || (strcmp(submod->rev[0].date, ret->rev[0].date) > 0))) {
484 ret = submod;
485 }
486 } else {
487 ret = submod;
488 }
489 } else {
490 /* store only if revision matches, we are done if it does */
491 if (!submod->rev) {
492 continue;
493 } else if (!strcmp(sub_revision, submod->rev[0].date)) {
494 ret = submod;
495 break;
496 }
497 }
Radek Krejcia7533f22016-03-07 07:37:45 +0100498 }
Radek Krejcic071c542016-01-27 14:57:51 +0100499
Michal Vaskof6d94c62016-04-05 11:21:54 +0200500 return ret;
Radek Krejciefaeba32015-05-27 14:30:57 +0200501}
502
Michal Vasko1e62a092015-12-01 12:27:20 +0100503static const struct lys_module *
Radek Krejcidfb00d62017-09-06 09:39:35 +0200504ly_ctx_get_module_by(const struct ly_ctx *ctx, const char *key, int offset, const char *revision, int with_disabled, int implemented)
Radek Krejciefaeba32015-05-27 14:30:57 +0200505{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200506 int i;
Radek Krejcib8048692015-08-05 13:36:34 +0200507 struct lys_module *result = NULL;
Radek Krejciefaeba32015-05-27 14:30:57 +0200508
Radek Krejcifd4e6e32015-08-10 15:00:51 +0200509 if (!ctx || !key) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200510 ly_errno = LY_EINVAL;
511 return NULL;
512 }
Radek Krejciefaeba32015-05-27 14:30:57 +0200513
Radek Krejcidce51452015-06-16 15:20:08 +0200514 for (i = 0; i < ctx->models.used; i++) {
Radek Krejci0ec51da2016-12-14 16:42:03 +0100515 if (!with_disabled && ctx->models.list[i]->disabled) {
516 /* skip the disabled modules */
517 continue;
518 }
Radek Krejcifd4e6e32015-08-10 15:00:51 +0200519 /* use offset to get address of the pointer to string (char**), remember that offset is in
520 * bytes, so we have to cast the pointer to the module to (char*), finally, we want to have
521 * string not the pointer to string
522 */
523 if (!ctx->models.list[i] || strcmp(key, *(char**)(((char*)ctx->models.list[i]) + offset))) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200524 continue;
525 }
Radek Krejciefaeba32015-05-27 14:30:57 +0200526
Radek Krejcif647e612015-07-30 11:36:07 +0200527 if (!revision) {
528 /* compare revisons and remember the newest one */
529 if (result) {
530 if (!ctx->models.list[i]->rev_size) {
531 /* the current have no revision, keep the previous with some revision */
532 continue;
533 }
534 if (result->rev_size && strcmp(ctx->models.list[i]->rev[0].date, result->rev[0].date) < 0) {
535 /* the previous found matching module has a newer revision */
536 continue;
537 }
538 }
Radek Krejcidfb00d62017-09-06 09:39:35 +0200539 if (implemented) {
540 if (ctx->models.list[i]->implemented) {
541 /* we have the implemented revision */
542 result = ctx->models.list[i];
543 break;
544 } else {
545 /* do not remember the result, we are supposed to return the implemented revision
546 * not the newest one */
547 continue;
548 }
549 }
Radek Krejcif647e612015-07-30 11:36:07 +0200550
551 /* remember the current match and search for newer version */
552 result = ctx->models.list[i];
553 } else {
554 if (ctx->models.list[i]->rev_size && !strcmp(revision, ctx->models.list[i]->rev[0].date)) {
555 /* matching revision */
Michal Vasko97586502015-08-12 14:32:18 +0200556 result = ctx->models.list[i];
557 break;
Radek Krejcif647e612015-07-30 11:36:07 +0200558 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200559 }
560 }
Radek Krejciefaeba32015-05-27 14:30:57 +0200561
Radek Krejcif647e612015-07-30 11:36:07 +0200562 return result;
Radek Krejcifd4e6e32015-08-10 15:00:51 +0200563
564}
565
Michal Vasko1e62a092015-12-01 12:27:20 +0100566API const struct lys_module *
Radek Krejcidfb00d62017-09-06 09:39:35 +0200567ly_ctx_get_module_by_ns(const struct ly_ctx *ctx, const char *ns, const char *revision, int implemented)
Radek Krejcifd4e6e32015-08-10 15:00:51 +0200568{
Radek Krejcidfb00d62017-09-06 09:39:35 +0200569 return ly_ctx_get_module_by(ctx, ns, offsetof(struct lys_module, ns), revision, 0, implemented);
Radek Krejcifd4e6e32015-08-10 15:00:51 +0200570}
571
Michal Vasko1e62a092015-12-01 12:27:20 +0100572API const struct lys_module *
Radek Krejcidfb00d62017-09-06 09:39:35 +0200573ly_ctx_get_module(const struct ly_ctx *ctx, const char *name, const char *revision, int implemented)
Radek Krejcifd4e6e32015-08-10 15:00:51 +0200574{
Radek Krejcidfb00d62017-09-06 09:39:35 +0200575 return ly_ctx_get_module_by(ctx, name, offsetof(struct lys_module, name), revision, 0, implemented);
Radek Krejcida04f4a2015-05-21 12:54:09 +0200576}
Michal Vasko3ec07dc2015-06-30 15:51:30 +0200577
Radek Krejci21601a32016-03-07 11:39:27 +0100578API const struct lys_module *
579ly_ctx_get_module_older(const struct ly_ctx *ctx, const struct lys_module *module)
580{
581 int i;
582 const struct lys_module *result = NULL, *iter;
583
584 if (!ctx || !module || !module->rev_size) {
585 ly_errno = LY_EINVAL;
586 return NULL;
587 }
588
589
590 for (i = 0; i < ctx->models.used; i++) {
591 iter = ctx->models.list[i];
Radek Krejci0ec51da2016-12-14 16:42:03 +0100592 if (iter->disabled) {
593 /* skip the disabled modules */
594 continue;
595 }
Radek Krejci21601a32016-03-07 11:39:27 +0100596 if (iter == module || !iter->rev_size) {
597 /* iter is the module itself or iter has no revision */
598 continue;
599 }
600 if (!ly_strequal(module->name, iter->name, 0)) {
601 /* different module */
602 continue;
603 }
604 if (strcmp(iter->rev[0].date, module->rev[0].date) < 0) {
605 /* iter is older than module */
606 if (result) {
607 if (strcmp(iter->rev[0].date, result->rev[0].date) > 0) {
608 /* iter is newer than current result */
609 result = iter;
610 }
611 } else {
612 result = iter;
613 }
614 }
615 }
616
617 return result;
618}
619
Michal Vasko99b0aad2015-12-01 12:28:51 +0100620API void
Michal Vaskoca28aab2017-01-13 13:50:12 +0100621ly_ctx_set_module_imp_clb(struct ly_ctx *ctx, ly_module_imp_clb clb, void *user_data)
Michal Vasko82465962015-11-10 11:03:11 +0100622{
Michal Vaskoad9f92a2017-04-06 09:49:07 +0200623 if (!ctx) {
624 ly_errno = LY_EINVAL;
625 return;
626 }
627
Michal Vaskof53187d2017-01-13 13:23:14 +0100628 ctx->imp_clb = clb;
629 ctx->imp_clb_data = user_data;
Michal Vasko99b0aad2015-12-01 12:28:51 +0100630}
631
Michal Vaskof53187d2017-01-13 13:23:14 +0100632API ly_module_imp_clb
Michal Vaskoca28aab2017-01-13 13:50:12 +0100633ly_ctx_get_module_imp_clb(const struct ly_ctx *ctx, void **user_data)
Michal Vasko99b0aad2015-12-01 12:28:51 +0100634{
Radek Krejciee554172016-12-14 10:29:06 +0100635 if (!ctx) {
636 ly_errno = LY_EINVAL;
637 return NULL;
638 }
639
Michal Vasko99b0aad2015-12-01 12:28:51 +0100640 if (user_data) {
Michal Vaskof53187d2017-01-13 13:23:14 +0100641 *user_data = ctx->imp_clb_data;
Michal Vasko99b0aad2015-12-01 12:28:51 +0100642 }
Michal Vaskof53187d2017-01-13 13:23:14 +0100643 return ctx->imp_clb;
644}
645
646API void
Michal Vaskoca28aab2017-01-13 13:50:12 +0100647ly_ctx_set_module_data_clb(struct ly_ctx *ctx, ly_module_data_clb clb, void *user_data)
Michal Vaskof53187d2017-01-13 13:23:14 +0100648{
Michal Vaskoad9f92a2017-04-06 09:49:07 +0200649 if (!ctx) {
650 ly_errno = LY_EINVAL;
651 return;
652 }
653
Michal Vaskof53187d2017-01-13 13:23:14 +0100654 ctx->data_clb = clb;
655 ctx->data_clb_data = user_data;
656}
657
658API ly_module_data_clb
Michal Vaskoca28aab2017-01-13 13:50:12 +0100659ly_ctx_get_module_data_clb(const struct ly_ctx *ctx, void **user_data)
Michal Vaskof53187d2017-01-13 13:23:14 +0100660{
Michal Vaskoad9f92a2017-04-06 09:49:07 +0200661 if (!ctx) {
662 ly_errno = LY_EINVAL;
663 return NULL;
664 }
665
Michal Vaskof53187d2017-01-13 13:23:14 +0100666 if (user_data) {
667 *user_data = ctx->data_clb_data;
668 }
669 return ctx->data_clb;
Michal Vasko99b0aad2015-12-01 12:28:51 +0100670}
671
Radek Krejcibf4e4652016-10-21 15:44:13 +0200672const struct lys_module *
Michal Vasko84475152016-07-25 16:16:25 +0200673ly_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 +0200674 int implement, struct unres_schema *unres)
Michal Vasko99b0aad2015-12-01 12:28:51 +0100675{
Michal Vasko8f3160e2017-09-27 11:25:26 +0200676 struct lys_module *mod;
677 char *module_data = NULL;
Radek Krejci03203412016-06-23 15:20:53 +0200678 int i;
Michal Vaskod3e975b2016-03-03 15:40:21 +0100679 void (*module_data_free)(void *module_data) = NULL;
Michal Vasko99b0aad2015-12-01 12:28:51 +0100680 LYS_INFORMAT format = LYS_IN_UNKNOWN;
Michal Vasko82465962015-11-10 11:03:11 +0100681
Michal Vasko84475152016-07-25 16:16:25 +0200682 if (!module) {
Radek Krejcibf4e4652016-10-21 15:44:13 +0200683 /* exception for internal modules */
Radek Krejcidfb00d62017-09-06 09:39:35 +0200684 for (i = 0; i < ctx->internal_module_count; i++) {
Michal Vasko84475152016-07-25 16:16:25 +0200685 if (ly_strequal(name, internal_modules[i].name, 0)) {
686 if (!revision || ly_strequal(revision, internal_modules[i].revision, 0)) {
687 /* return internal module */
Radek Krejcidfb00d62017-09-06 09:39:35 +0200688 return (struct lys_module *)ly_ctx_get_module(ctx, name, revision, 0);
Michal Vasko84475152016-07-25 16:16:25 +0200689 }
Radek Krejci03203412016-06-23 15:20:53 +0200690 }
691 }
Michal Vasko8f3160e2017-09-27 11:25:26 +0200692 /* try to get the schema from the context (with or without revision),
693 * include the disabled modules in the search to avoid their duplication,
694 * they are enabled by the subsequent call to lys_set_implemented() */
695 for (i = ctx->internal_module_count, mod = NULL; i < ctx->models.used; i++) {
696 mod = ctx->models.list[i]; /* shortcut */
697 if (ly_strequal(name, mod->name, 0)) {
698 if (revision && mod->rev_size && !strcmp(revision, mod->rev[0].date)) {
699 /* the specific revision was already loaded */
700 break;
701 } else if (!revision && mod->latest_revision) {
702 /* the latest revision of this module was already loaded */
Radek Krejci0ec51da2016-12-14 16:42:03 +0100703 break;
Radek Krejci44564912017-10-31 16:49:29 +0100704 } else if (implement && mod->implemented && !revision) {
705 /* we are not able to implement another module, so consider this module as the latest one */
706 break;
Radek Krejci0ec51da2016-12-14 16:42:03 +0100707 }
Michal Vasko8f3160e2017-09-27 11:25:26 +0200708 }
709 mod = NULL;
710 }
711 if (mod) {
712 /* module must be enabled */
713 if (mod->disabled) {
714 lys_set_enabled(mod);
715 }
716 /* module is supposed to be implemented */
717 if (implement && lys_set_implemented(mod)) {
718 /* the schema cannot be implemented */
Radek Krejci0ec51da2016-12-14 16:42:03 +0100719 mod = NULL;
720 }
Michal Vasko8f3160e2017-09-27 11:25:26 +0200721 return mod;
Radek Krejcibf4e4652016-10-21 15:44:13 +0200722 }
Radek Krejci03203412016-06-23 15:20:53 +0200723 }
724
Michal Vasko8f3160e2017-09-27 11:25:26 +0200725 /* module is not yet in context, use the user callback or try to find the schema on our own */
Michal Vaskof53187d2017-01-13 13:23:14 +0100726 if (ctx->imp_clb) {
Michal Vasko8f3160e2017-09-27 11:25:26 +0200727 ly_errno = LY_SUCCESS;
Michal Vasko84475152016-07-25 16:16:25 +0200728 if (module) {
729 mod = lys_main_module(module);
Michal Vaskof53187d2017-01-13 13:23:14 +0100730 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 +0200731 } else {
Michal Vaskof53187d2017-01-13 13:23:14 +0100732 module_data = ctx->imp_clb(name, revision, NULL, NULL, ctx->imp_clb_data, &format, &module_data_free);
Michal Vasko84475152016-07-25 16:16:25 +0200733 }
Michal Vasko8f3160e2017-09-27 11:25:26 +0200734 if (!module_data && (ly_errno != LY_SUCCESS)) {
735 /* callback encountered an error, do not change it */
736 LOGERR(LY_SUCCESS, "User module retrieval callback failed!");
737 return NULL;
Michal Vasko82465962015-11-10 11:03:11 +0100738 }
Michal Vasko8f3160e2017-09-27 11:25:26 +0200739 }
Michal Vasko84475152016-07-25 16:16:25 +0200740
Michal Vasko8f3160e2017-09-27 11:25:26 +0200741 if (module_data) {
742 /* we got the module from the callback */
Michal Vasko84475152016-07-25 16:16:25 +0200743 if (module) {
Michal Vasko5b998712017-01-26 10:34:06 +0100744 mod = (struct lys_module *)lys_sub_parse_mem(module, module_data, format, unres);
Michal Vasko84475152016-07-25 16:16:25 +0200745 } else {
Michal Vasko29245662017-04-18 15:56:31 +0200746 mod = (struct lys_module *)lys_parse_mem_(ctx, module_data, format, 0, implement);
Michal Vasko84475152016-07-25 16:16:25 +0200747 }
748
Michal Vasko99b0aad2015-12-01 12:28:51 +0100749 if (module_data_free) {
750 module_data_free(module_data);
Michal Vasko82465962015-11-10 11:03:11 +0100751 }
Michal Vasko99b0aad2015-12-01 12:28:51 +0100752 } else {
Michal Vasko8f3160e2017-09-27 11:25:26 +0200753 /* module was not received from the callback or there is no callback set */
Michal Vasko58e5f3e2016-07-28 11:06:34 +0200754 mod = lyp_search_file(ctx, module, name, revision, implement, unres);
Michal Vasko82465962015-11-10 11:03:11 +0100755 }
756
Michal Vasko8f3160e2017-09-27 11:25:26 +0200757#ifdef LY_ENABLED_LATEST_REVISIONS
758 if (!revision && mod) {
759 /* module is the latest revision found */
760 mod->latest_revision = 1;
761 }
762#endif
763
Michal Vasko84475152016-07-25 16:16:25 +0200764 return mod;
765}
766
767API const struct lys_module *
768ly_ctx_load_module(struct ly_ctx *ctx, const char *name, const char *revision)
769{
770 if (!ctx || !name) {
771 ly_errno = LY_EINVAL;
772 return NULL;
773 }
774
Radek Krejci05f15982017-06-13 15:26:10 +0200775 return ly_ctx_load_sub_module(ctx, NULL, name, revision && revision[0] ? revision : NULL, 1, NULL);
Michal Vasko82465962015-11-10 11:03:11 +0100776}
777
Radek Krejci85a54be2016-10-20 12:39:56 +0200778/*
779 * mods - set of removed modules, if NULL all modules are supposed to be removed so any backlink is invalid
780 */
Michal Vasko4be5fa22017-02-07 10:12:32 +0100781static void
782ctx_modules_undo_backlinks(struct ly_ctx *ctx, struct ly_set *mods)
Radek Krejci85a54be2016-10-20 12:39:56 +0200783{
784 int o;
785 uint8_t j;
786 unsigned int u, v;
787 struct lys_module *mod;
788 struct lys_node *elem, *next;
789 struct lys_node_leaf *leaf;
790
791 /* maintain backlinks (start with internal ietf-yang-library which have leafs as possible targets of leafrefs */
Radek Krejcidfb00d62017-09-06 09:39:35 +0200792 for (o = ctx->internal_module_count - 1; o < ctx->models.used; o++) {
Radek Krejci85a54be2016-10-20 12:39:56 +0200793 mod = ctx->models.list[o]; /* shortcut */
794
795 /* 1) features */
796 for (j = 0; j < mod->features_size; j++) {
797 if (!mod->features[j].depfeatures) {
798 continue;
799 }
800 for (v = 0; v < mod->features[j].depfeatures->number; v++) {
801 if (!mods || ly_set_contains(mods, ((struct lys_feature *)mod->features[j].depfeatures->set.g[v])->module) != -1) {
802 /* depending feature is in module to remove */
803 ly_set_rm_index(mod->features[j].depfeatures, v);
804 v--;
805 }
806 }
807 if (!mod->features[j].depfeatures->number) {
808 /* all backlinks removed */
809 ly_set_free(mod->features[j].depfeatures);
810 mod->features[j].depfeatures = NULL;
811 }
812 }
Michal Vasko4be5fa22017-02-07 10:12:32 +0100813
814 /* 2) identities */
Radek Krejci85a54be2016-10-20 12:39:56 +0200815 for (u = 0; u < mod->ident_size; u++) {
816 if (!mod->ident[u].der) {
817 continue;
818 }
819 for (v = 0; v < mod->ident[u].der->number; v++) {
820 if (!mods || ly_set_contains(mods, ((struct lys_ident *)mod->ident[u].der->set.g[v])->module) != -1) {
821 /* derived identity is in module to remove */
822 ly_set_rm_index(mod->ident[u].der, v);
823 v--;
824 }
825 }
826 if (!mod->ident[u].der->number) {
827 /* all backlinks removed */
828 ly_set_free(mod->ident[u].der);
829 mod->ident[u].der = NULL;
830 }
831 }
832
Michal Vasko4be5fa22017-02-07 10:12:32 +0100833 /* 3) leafrefs */
Radek Krejci85a54be2016-10-20 12:39:56 +0200834 for (elem = next = mod->data; elem; elem = next) {
835 if (elem->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
836 leaf = (struct lys_node_leaf *)elem; /* shortcut */
837 if (leaf->backlinks) {
838 if (!mods) {
839 /* remove all backlinks */
840 ly_set_free(leaf->backlinks);
841 leaf->backlinks = NULL;
842 } else {
843 for (v = 0; v < leaf->backlinks->number; v++) {
844 if (ly_set_contains(mods, leaf->backlinks->set.s[v]->module) != -1) {
845 /* derived identity is in module to remove */
846 ly_set_rm_index(leaf->backlinks, v);
847 v--;
848 }
849 }
850 if (!leaf->backlinks->number) {
851 /* all backlinks removed */
852 ly_set_free(leaf->backlinks);
853 leaf->backlinks = NULL;
854 }
855 }
856 }
857 }
858
859 /* select next element to process */
860 next = elem->child;
861 /* child exception for leafs, leaflists, anyxml and groupings */
862 if (elem->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA | LYS_GROUPING)) {
863 next = NULL;
864 }
865 if (!next) {
866 /* no children, try siblings */
867 next = elem->next;
868 }
869 while (!next) {
870 /* parent is already processed, go to its sibling */
871 elem = lys_parent(elem);
872 if (!elem) {
873 /* we are done, no next element to process */
874 break;
875 }
876 /* no siblings, go back through parents */
877 next = elem->next;
878 }
879 }
880 }
Michal Vasko4be5fa22017-02-07 10:12:32 +0100881}
Radek Krejci85a54be2016-10-20 12:39:56 +0200882
Michal Vasko4be5fa22017-02-07 10:12:32 +0100883static int
Radek Krejci83a4bac2017-02-07 15:53:04 +0100884ctx_modules_redo_backlinks(struct ly_set *mods)
Michal Vasko4be5fa22017-02-07 10:12:32 +0100885{
Radek Krejci83a4bac2017-02-07 15:53:04 +0100886 unsigned int i, j, k, s;
887 struct lys_module *mod;
888 struct lys_node *next, *elem;
889 struct lys_type *type;
890 struct lys_feature *feat;
Michal Vasko4be5fa22017-02-07 10:12:32 +0100891
Michal Vasko4be5fa22017-02-07 10:12:32 +0100892 for (i = 0; i < mods->number; ++i) {
Radek Krejci83a4bac2017-02-07 15:53:04 +0100893 mod = (struct lys_module *)mods->set.g[i]; /* shortcut */
Michal Vasko4be5fa22017-02-07 10:12:32 +0100894
Radek Krejci83a4bac2017-02-07 15:53:04 +0100895 /* identities */
Radek Krejci9e6af732017-04-27 14:40:25 +0200896 if (mod->implemented) {
897 for (j = 0; j < mod->ident_size; j++) {
898 for (k = 0; k < mod->ident[j].base_size; k++) {
899 resolve_identity_backlink_update(&mod->ident[j], mod->ident[j].base[k]);
900 }
Radek Krejci83a4bac2017-02-07 15:53:04 +0100901 }
902 }
Michal Vasko4be5fa22017-02-07 10:12:32 +0100903
Radek Krejci83a4bac2017-02-07 15:53:04 +0100904 /* features */
905 for (j = 0; j < mod->features_size; j++) {
906 for (k = 0; k < mod->features[j].iffeature_size; k++) {
907 resolve_iffeature_getsizes(&mod->features[j].iffeature[k], NULL, &s);
908 while (s--) {
909 feat = mod->features[j].iffeature[k].features[s]; /* shortcut */
910 if (!feat->depfeatures) {
911 feat->depfeatures = ly_set_new();
912 }
913 ly_set_add(feat->depfeatures, &mod->features[j], LY_SET_OPT_USEASLIST);
914 }
915 }
916 }
917
918 /* leafrefs */
919 LY_TREE_DFS_BEGIN(mod->data, next, elem) {
Michal Vaskofa3d2f72017-04-10 13:30:44 +0200920 if (elem->nodetype == LYS_GROUPING) {
921 goto next_sibling;
922 }
923
Radek Krejci83a4bac2017-02-07 15:53:04 +0100924 if (elem->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
925 type = &((struct lys_node_leaf *)elem)->type; /* shortcut */
926 if (type->base == LY_TYPE_LEAFREF) {
927 lys_leaf_add_leafref_target(type->info.lref.target, elem);
928 }
929 }
930
Michal Vaskofa3d2f72017-04-10 13:30:44 +0200931 /* select element for the next run - children first */
932 next = elem->child;
933
934 /* child exception for leafs, leaflists and anyxml without children */
935 if (elem->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
936 next = NULL;
937 }
938 if (!next) {
939next_sibling:
940 /* no children */
941 if (elem == mod->data) {
942 /* we are done, (START) has no children */
943 break;
944 }
945 /* try siblings */
946 next = elem->next;
947 }
948 while (!next) {
949 /* parent is already processed, go to its sibling */
950 elem = lys_parent(elem);
951
952 /* no siblings, go back through parents */
953 if (lys_parent(elem) == lys_parent(mod->data)) {
954 /* we are done, no next element to process */
955 break;
956 }
957 next = elem->next;
958 }
Radek Krejci83a4bac2017-02-07 15:53:04 +0100959 }
Michal Vasko4be5fa22017-02-07 10:12:32 +0100960 }
961
962 return 0;
Radek Krejci85a54be2016-10-20 12:39:56 +0200963}
964
Radek Krejci8c107fe2016-10-17 16:00:18 +0200965API int
Radek Krejci0ec51da2016-12-14 16:42:03 +0100966lys_set_disabled(const struct lys_module *module)
967{
968 struct ly_ctx *ctx; /* shortcut */
969 struct lys_module *mod;
970 struct ly_set *mods;
971 uint8_t j, imported;
972 int i, o;
Radek Krejci29eac3d2017-06-01 16:50:02 +0200973 unsigned int u, v;
Radek Krejci0ec51da2016-12-14 16:42:03 +0100974
975 if (!module) {
976 ly_errno = LY_EINVAL;
977 return EXIT_FAILURE;
978 } else if (module->disabled) {
979 /* already disabled module */
980 return EXIT_SUCCESS;
981 }
982 mod = (struct lys_module *)module;
983 ctx = mod->ctx;
984
985 /* avoid disabling internal modules */
Radek Krejcidfb00d62017-09-06 09:39:35 +0200986 for (i = 0; i < ctx->internal_module_count; i++) {
Radek Krejci0ec51da2016-12-14 16:42:03 +0100987 if (mod == ctx->models.list[i]) {
Michal Vasko2d051a12017-04-21 09:28:57 +0200988 LOGERR(LY_EINVAL, "Internal module \"%s\" cannot be disabled.", mod->name);
Radek Krejci0ec51da2016-12-14 16:42:03 +0100989 return EXIT_FAILURE;
990 }
991 }
992
993 /* disable the module */
994 mod->disabled = 1;
995
996 /* get the complete list of modules to disable because of dependencies,
997 * we are going also to disable all the imported (not implemented) modules
998 * that are not used in any other module */
999 mods = ly_set_new();
1000 ly_set_add(mods, mod, 0);
1001checkdependency:
Radek Krejcidfb00d62017-09-06 09:39:35 +02001002 for (i = ctx->internal_module_count; i < ctx->models.used; i++) {
Radek Krejci0ec51da2016-12-14 16:42:03 +01001003 mod = ctx->models.list[i]; /* shortcut */
1004 if (mod->disabled) {
1005 /* skip the already disabled modules */
1006 continue;
1007 }
1008
1009 /* check depndency of imported modules */
1010 for (j = 0; j < mod->imp_size; j++) {
1011 for (u = 0; u < mods->number; u++) {
1012 if (mod->imp[j].module == mods->set.g[u]) {
1013 /* module is importing some module to disable, so it must be also disabled */
1014 mod->disabled = 1;
1015 ly_set_add(mods, mod, 0);
1016 /* we have to start again because some of the already checked modules can
1017 * depend on the one we have just decided to disable */
1018 goto checkdependency;
1019 }
1020 }
1021 }
1022 /* check if the imported module is used in any module supposed to be kept */
1023 if (!mod->implemented) {
1024 imported = 0;
Radek Krejcidfb00d62017-09-06 09:39:35 +02001025 for (o = ctx->internal_module_count; o < ctx->models.used; o++) {
Radek Krejci0ec51da2016-12-14 16:42:03 +01001026 if (ctx->models.list[o]->disabled) {
1027 /* skip modules already disabled */
1028 continue;
1029 }
1030 for (j = 0; j < ctx->models.list[o]->imp_size; j++) {
1031 if (ctx->models.list[o]->imp[j].module == mod) {
1032 /* the module is used in some other module not yet selected to be disabled */
1033 imported = 1;
1034 goto imported;
1035 }
1036 }
1037 }
1038imported:
1039 if (!imported) {
1040 /* module is not implemented and neither imported by any other module in context
1041 * which is supposed to be kept enabled after this operation, so we are going to disable also
1042 * this module */
1043 mod->disabled = 1;
1044 ly_set_add(mods, mod, 0);
1045 /* we have to start again, this time not because other module can depend on this one
1046 * (we know that there is no such module), but because the module can import module
1047 * that could became useless. If there are no imports, we can continue */
1048 if (mod->imp_size) {
1049 goto checkdependency;
1050 }
1051 }
1052 }
1053 }
1054
1055 /* before removing applied deviations, augments and updating leafrefs, we have to enable the modules
1056 * to disable to allow all that operations */
1057 for (u = 0; u < mods->number; u++) {
1058 ((struct lys_module *)mods->set.g[u])->disabled = 0;
1059 }
1060
1061 /* maintain backlinks (start with internal ietf-yang-library which have leafs as possible targets of leafrefs */
Michal Vasko4be5fa22017-02-07 10:12:32 +01001062 ctx_modules_undo_backlinks(ctx, mods);
Radek Krejci0ec51da2016-12-14 16:42:03 +01001063
1064 /* remove the applied deviations and augments */
1065 for (u = 0; u < mods->number; u++) {
1066 lys_sub_module_remove_devs_augs((struct lys_module *)mods->set.g[u]);
1067 }
1068
Radek Krejci29eac3d2017-06-01 16:50:02 +02001069 /* now again disable the modules to disable and disable also all its submodules */
Radek Krejci0ec51da2016-12-14 16:42:03 +01001070 for (u = 0; u < mods->number; u++) {
Radek Krejci29eac3d2017-06-01 16:50:02 +02001071 mod = (struct lys_module *)mods->set.g[u];
1072 mod->disabled = 1;
1073 for (v = 0; v < mod->inc_size; v++) {
1074 mod->inc[v].submodule->disabled = 1;
1075 }
Radek Krejci0ec51da2016-12-14 16:42:03 +01001076 }
1077
1078 /* free the set */
1079 ly_set_free(mods);
1080
1081 /* update the module-set-id */
1082 ctx->models.module_set_id++;
1083
1084 return EXIT_SUCCESS;
1085}
1086
1087static void
1088lys_set_enabled_(struct ly_set *mods, struct lys_module *mod)
1089{
1090 unsigned int i;
1091
1092 ly_set_add(mods, mod, 0);
1093 mod->disabled = 0;
1094
Radek Krejci29eac3d2017-06-01 16:50:02 +02001095 for (i = 0; i < mod->inc_size; i++) {
1096 mod->inc[i].submodule->disabled = 0;
1097 }
1098
Radek Krejci0ec51da2016-12-14 16:42:03 +01001099 /* go recursively */
1100 for (i = 0; i < mod->imp_size; i++) {
1101 if (!mod->imp[i].module->disabled) {
1102 continue;
1103 }
1104
1105 lys_set_enabled_(mods, mod->imp[i].module);
1106 }
1107}
1108
1109API int
1110lys_set_enabled(const struct lys_module *module)
1111{
1112 struct ly_ctx *ctx; /* shortcut */
1113 struct lys_module *mod;
1114 struct ly_set *mods, *disabled;
1115 int i;
Radek Krejci29eac3d2017-06-01 16:50:02 +02001116 unsigned int u, v, w;
Radek Krejci0ec51da2016-12-14 16:42:03 +01001117
1118 if (!module) {
1119 ly_errno = LY_EINVAL;
1120 return EXIT_FAILURE;
1121 } else if (!module->disabled) {
1122 /* already enabled module */
1123 return EXIT_SUCCESS;
1124 }
1125 mod = (struct lys_module *)module;
1126 ctx = mod->ctx;
1127
1128 /* avoid disabling internal modules */
Radek Krejcidfb00d62017-09-06 09:39:35 +02001129 for (i = 0; i < ctx->internal_module_count; i++) {
Radek Krejci0ec51da2016-12-14 16:42:03 +01001130 if (mod == ctx->models.list[i]) {
1131 LOGERR(LY_EINVAL, "Internal module \"%s\" cannot be removed.", mod->name);
1132 return EXIT_FAILURE;
1133 }
1134 }
1135
1136 mods = ly_set_new();
1137 disabled = ly_set_new();
1138
1139 /* enable the module, including its dependencies */
1140 lys_set_enabled_(mods, mod);
1141
1142 /* we will go through the all disabled modules in the context, if the module has no dependency (import)
1143 * that is still disabled AND at least one of its imported module is from the set we are enabling now,
1144 * it is going to be also enabled. This way we try to revert everething that was possibly done by
1145 * lys_set_disabled(). */
1146checkdependency:
Radek Krejcidfb00d62017-09-06 09:39:35 +02001147 for (i = ctx->internal_module_count; i < ctx->models.used; i++) {
Radek Krejci0ec51da2016-12-14 16:42:03 +01001148 mod = ctx->models.list[i]; /* shortcut */
1149 if (!mod->disabled || ly_set_contains(disabled, mod) != -1) {
1150 /* skip the enabled modules */
1151 continue;
1152 }
1153
1154 /* check imported modules */
1155 for (u = 0; u < mod->imp_size; u++) {
1156 if (mod->imp[u].module->disabled) {
1157 /* it has disabled dependency so it must stay disabled */
1158 break;
1159 }
1160 }
1161 if (u < mod->imp_size) {
1162 /* it has disabled dependency, continue with the next module in the context */
1163 continue;
1164 }
1165
1166 /* get know if at least one of the imported modules is being enabled this time */
1167 for (u = 0; u < mod->imp_size; u++) {
1168 for (v = 0; v < mods->number; v++) {
1169 if (mod->imp[u].module == mods->set.g[v]) {
1170 /* yes, it is, so they are connected and we are going to enable it as well,
1171 * it is not necessary to call recursive lys_set_enable_() because we already
1172 * know that there is no disabled import to enable */
1173 mod->disabled = 0;
1174 ly_set_add(mods, mod, 0);
Radek Krejci29eac3d2017-06-01 16:50:02 +02001175 for (w = 0; w < mod->inc_size; w++) {
1176 mod->inc[w].submodule->disabled = 0;
1177 }
Radek Krejci0ec51da2016-12-14 16:42:03 +01001178 /* we have to start again because some of the already checked modules can
1179 * depend on the one we have just decided to enable */
1180 goto checkdependency;
1181 }
1182 }
1183 }
1184
1185 /* this module is disabled, but it does not depend on any other disabled module and none
1186 * of its imports was not enabled in this call. No future enabling of the disabled module
1187 * will change this so we can remember the module and skip it next time we will have to go
1188 * through the all context because of the checkdependency goto.
1189 */
1190 ly_set_add(disabled, mod, 0);
1191 }
1192
1193 /* maintain backlinks (start with internal ietf-yang-library which have leafs as possible targets of leafrefs */
Radek Krejci83a4bac2017-02-07 15:53:04 +01001194 ctx_modules_redo_backlinks(mods);
Radek Krejci0ec51da2016-12-14 16:42:03 +01001195
1196 /* re-apply the deviations and augments */
1197 for (v = 0; v < mods->number; v++) {
1198 lys_sub_module_apply_devs_augs((struct lys_module *)mods->set.g[v]);
1199 }
1200
1201 /* free the sets */
1202 ly_set_free(mods);
1203 ly_set_free(disabled);
1204
1205 /* update the module-set-id */
1206 ctx->models.module_set_id++;
1207
1208 return EXIT_SUCCESS;
1209}
1210
1211API int
1212ly_ctx_remove_module(const struct lys_module *module,
Radek Krejci8c107fe2016-10-17 16:00:18 +02001213 void (*private_destructor)(const struct lys_node *node, void *priv))
1214{
Radek Krejci0ec51da2016-12-14 16:42:03 +01001215 struct ly_ctx *ctx; /* shortcut */
Radek Krejci8c107fe2016-10-17 16:00:18 +02001216 struct lys_module *mod = NULL;
1217 struct ly_set *mods;
1218 uint8_t j, imported;
1219 int i, o;
1220 unsigned int u;
1221
Radek Krejci0ec51da2016-12-14 16:42:03 +01001222 if (!module) {
Radek Krejci8c107fe2016-10-17 16:00:18 +02001223 ly_errno = LY_EINVAL;
1224 return EXIT_FAILURE;
1225 }
1226
Radek Krejci0ec51da2016-12-14 16:42:03 +01001227 mod = (struct lys_module *)module;
1228 ctx = mod->ctx;
1229
Radek Krejci8c107fe2016-10-17 16:00:18 +02001230 /* avoid removing internal modules ... */
Radek Krejcidfb00d62017-09-06 09:39:35 +02001231 for (i = 0; i < ctx->internal_module_count; i++) {
Radek Krejci8c107fe2016-10-17 16:00:18 +02001232 if (mod == ctx->models.list[i]) {
Radek Krejci0ec51da2016-12-14 16:42:03 +01001233 LOGERR(LY_EINVAL, "Internal module \"%s\" cannot be removed.", mod->name);
Radek Krejci8c107fe2016-10-17 16:00:18 +02001234 return EXIT_FAILURE;
1235 }
1236 }
1237 /* ... and hide the module from the further processing of the context modules list */
Radek Krejcidfb00d62017-09-06 09:39:35 +02001238 for (i = ctx->internal_module_count; i < ctx->models.used; i++) {
Radek Krejci8c107fe2016-10-17 16:00:18 +02001239 if (mod == ctx->models.list[i]) {
1240 ctx->models.list[i] = NULL;
1241 break;
1242 }
1243 }
1244
1245 /* get the complete list of modules to remove because of dependencies,
1246 * we are going also to remove all the imported (not implemented) modules
1247 * that are not used in any other module */
1248 mods = ly_set_new();
1249 ly_set_add(mods, mod, 0);
1250checkdependency:
Radek Krejcidfb00d62017-09-06 09:39:35 +02001251 for (i = ctx->internal_module_count; i < ctx->models.used; i++) {
Radek Krejci8c107fe2016-10-17 16:00:18 +02001252 mod = ctx->models.list[i]; /* shortcut */
1253 if (!mod) {
1254 /* skip modules already selected for removing */
1255 continue;
1256 }
1257
1258 /* check depndency of imported modules */
1259 for (j = 0; j < mod->imp_size; j++) {
1260 for (u = 0; u < mods->number; u++) {
1261 if (mod->imp[j].module == mods->set.g[u]) {
1262 /* module is importing some module to remove, so it must be also removed */
1263 ly_set_add(mods, mod, 0);
1264 ctx->models.list[i] = NULL;
1265 /* we have to start again because some of the already checked modules can
1266 * depend on the one we have just decided to remove */
1267 goto checkdependency;
1268 }
1269 }
1270 }
1271 /* check if the imported module is used in any module supposed to be kept */
1272 if (!mod->implemented) {
1273 imported = 0;
Radek Krejcidfb00d62017-09-06 09:39:35 +02001274 for (o = ctx->internal_module_count; o < ctx->models.used; o++) {
Radek Krejci8c107fe2016-10-17 16:00:18 +02001275 if (!ctx->models.list[o]) {
1276 /* skip modules already selected for removing */
1277 continue;
1278 }
1279 for (j = 0; j < ctx->models.list[o]->imp_size; j++) {
1280 if (ctx->models.list[o]->imp[j].module == mod) {
1281 /* the module is used in some other module not yet selected to be deleted */
1282 imported = 1;
1283 goto imported;
1284 }
1285 }
1286 }
1287imported:
1288 if (!imported) {
1289 /* module is not implemented and neither imported by any other module in context
1290 * which is supposed to be kept after this operation, so we are going to remove also
1291 * this useless module */
1292 ly_set_add(mods, mod, 0);
1293 ctx->models.list[i] = NULL;
1294 /* we have to start again, this time not because other module can depend on this one
Radek Krejci0ec51da2016-12-14 16:42:03 +01001295 * (we know that there is no such module), but because the module can import module
Radek Krejci8c107fe2016-10-17 16:00:18 +02001296 * that could became useless. If there are no imports, we can continue */
1297 if (mod->imp_size) {
1298 goto checkdependency;
1299 }
1300 }
1301 }
1302 }
1303
Radek Krejci8c107fe2016-10-17 16:00:18 +02001304
1305 /* consolidate the modules list */
Radek Krejcidfb00d62017-09-06 09:39:35 +02001306 for (i = o = ctx->internal_module_count; i < ctx->models.used; i++) {
Radek Krejci8c107fe2016-10-17 16:00:18 +02001307 if (ctx->models.list[o]) {
1308 /* used cell */
1309 o++;
1310 } else {
1311 /* the current output cell is empty, move here an input cell */
1312 ctx->models.list[o] = ctx->models.list[i];
1313 ctx->models.list[i] = NULL;
1314 }
1315 }
1316 /* get the last used cell to get know the number of used */
1317 while (!ctx->models.list[o]) {
1318 o--;
1319 }
1320 ctx->models.used = o + 1;
1321 ctx->models.module_set_id++;
1322
Radek Krejci85a54be2016-10-20 12:39:56 +02001323 /* maintain backlinks (start with internal ietf-yang-library which have leafs as possible targets of leafrefs */
Michal Vasko4be5fa22017-02-07 10:12:32 +01001324 ctx_modules_undo_backlinks(ctx, mods);
Radek Krejci85a54be2016-10-20 12:39:56 +02001325
1326 /* free the modules */
1327 for (u = 0; u < mods->number; u++) {
Radek Krejcib2541a32016-12-12 16:45:57 +01001328 /* remove the applied deviations and augments */
1329 lys_sub_module_remove_devs_augs((struct lys_module *)mods->set.g[u]);
Radek Krejci85a54be2016-10-20 12:39:56 +02001330 /* remove the module */
1331 lys_free((struct lys_module *)mods->set.g[u], private_destructor, 0);
1332 }
1333 ly_set_free(mods);
1334
Radek Krejci8c107fe2016-10-17 16:00:18 +02001335 return EXIT_SUCCESS;
1336}
1337
Radek Krejci85a54be2016-10-20 12:39:56 +02001338API void
1339ly_ctx_clean(struct ly_ctx *ctx, void (*private_destructor)(const struct lys_node *node, void *priv))
1340{
Radek Krejci85a54be2016-10-20 12:39:56 +02001341 if (!ctx) {
1342 return;
1343 }
1344
1345 /* models list */
Radek Krejcidfb00d62017-09-06 09:39:35 +02001346 for (; ctx->models.used > ctx->internal_module_count; ctx->models.used--) {
Radek Krejcifc8411a2017-02-03 10:26:05 +01001347 /* remove the applied deviations and augments */
Radek Krejcic436a232017-02-08 14:43:11 +01001348 lys_sub_module_remove_devs_augs(ctx->models.list[ctx->models.used - 1]);
Radek Krejcifc8411a2017-02-03 10:26:05 +01001349 /* remove the module */
Radek Krejcic436a232017-02-08 14:43:11 +01001350 lys_free(ctx->models.list[ctx->models.used - 1], private_destructor, 0);
Radek Krejcifc8411a2017-02-03 10:26:05 +01001351 /* clean it for safer future use */
Radek Krejcic436a232017-02-08 14:43:11 +01001352 ctx->models.list[ctx->models.used - 1] = NULL;
Radek Krejci85a54be2016-10-20 12:39:56 +02001353 }
Radek Krejci85a54be2016-10-20 12:39:56 +02001354 ctx->models.module_set_id++;
1355
Radek Krejci83a4bac2017-02-07 15:53:04 +01001356 /* maintain backlinks (actually done only with ietf-yang-library since its leafs can be target of leafref) */
Michal Vasko4be5fa22017-02-07 10:12:32 +01001357 ctx_modules_undo_backlinks(ctx, NULL);
Radek Krejci85a54be2016-10-20 12:39:56 +02001358}
1359
Michal Vaskod7957c02016-04-01 10:27:26 +02001360API const struct lys_module *
1361ly_ctx_get_module_iter(const struct ly_ctx *ctx, uint32_t *idx)
1362{
1363 if (!ctx || !idx) {
1364 ly_errno = LY_EINVAL;
1365 return NULL;
1366 }
1367
Radek Krejci0ec51da2016-12-14 16:42:03 +01001368 for ( ; *idx < (unsigned)ctx->models.used; (*idx)++) {
1369 if (!ctx->models.list[(*idx)]->disabled) {
1370 return ctx->models.list[(*idx)++];
1371 }
1372 }
1373
1374 return NULL;
1375}
1376
1377API const struct lys_module *
1378ly_ctx_get_disabled_module_iter(const struct ly_ctx *ctx, uint32_t *idx)
1379{
1380 if (!ctx || !idx) {
1381 ly_errno = LY_EINVAL;
Michal Vaskod7957c02016-04-01 10:27:26 +02001382 return NULL;
1383 }
1384
Radek Krejci0ec51da2016-12-14 16:42:03 +01001385 for ( ; *idx < (unsigned)ctx->models.used; (*idx)++) {
1386 if (ctx->models.list[(*idx)]->disabled) {
1387 return ctx->models.list[(*idx)++];
1388 }
1389 }
1390
1391 return NULL;
Michal Vaskod7957c02016-04-01 10:27:26 +02001392}
1393
Michal Vasko209a6222015-10-16 09:51:07 +02001394static int
1395ylib_feature(struct lyd_node *parent, struct lys_module *cur_mod)
1396{
1397 int i, j;
1398
1399 /* module features */
1400 for (i = 0; i < cur_mod->features_size; ++i) {
1401 if (!(cur_mod->features[i].flags & LYS_FENABLED)) {
1402 continue;
1403 }
1404
Michal Vasko3e671b52015-10-23 16:23:15 +02001405 if (!lyd_new_leaf(parent, NULL, "feature", cur_mod->features[i].name)) {
Michal Vasko209a6222015-10-16 09:51:07 +02001406 return EXIT_FAILURE;
1407 }
1408 }
1409
1410 /* submodule features */
Radek Krejcic071c542016-01-27 14:57:51 +01001411 for (i = 0; i < cur_mod->inc_size && cur_mod->inc[i].submodule; ++i) {
Michal Vasko209a6222015-10-16 09:51:07 +02001412 for (j = 0; j < cur_mod->inc[i].submodule->features_size; ++j) {
1413 if (!(cur_mod->inc[i].submodule->features[j].flags & LYS_FENABLED)) {
1414 continue;
1415 }
1416
Michal Vasko3e671b52015-10-23 16:23:15 +02001417 if (!lyd_new_leaf(parent, NULL, "feature", cur_mod->inc[i].submodule->features[j].name)) {
Michal Vasko209a6222015-10-16 09:51:07 +02001418 return EXIT_FAILURE;
1419 }
1420 }
1421 }
1422
1423 return EXIT_SUCCESS;
1424}
1425
1426static int
Michal Vaskoff006c12016-02-17 11:15:19 +01001427ylib_deviation(struct lyd_node *parent, struct lys_module *cur_mod)
Michal Vasko97d8c6d2016-02-12 11:05:48 +01001428{
Michal Vasko89563fc2016-07-28 16:19:35 +02001429 uint32_t i = 0, j;
1430 const struct lys_module *mod;
Michal Vasko209a6222015-10-16 09:51:07 +02001431 struct lyd_node *cont;
Michal Vasko89563fc2016-07-28 16:19:35 +02001432 const char *ptr;
Michal Vasko209a6222015-10-16 09:51:07 +02001433
Michal Vasko89563fc2016-07-28 16:19:35 +02001434 if (cur_mod->deviated) {
1435 while ((mod = ly_ctx_get_module_iter(cur_mod->ctx, &i))) {
1436 if (mod == cur_mod) {
1437 continue;
Michal Vasko209a6222015-10-16 09:51:07 +02001438 }
Michal Vasko209a6222015-10-16 09:51:07 +02001439
Michal Vasko89563fc2016-07-28 16:19:35 +02001440 for (j = 0; j < mod->deviation_size; ++j) {
1441 ptr = strstr(mod->deviation[j].target_name, cur_mod->name);
1442 if (ptr && ptr[strlen(cur_mod->name)] == ':') {
1443 cont = lyd_new(parent, NULL, "deviation");
1444 if (!cont) {
1445 return EXIT_FAILURE;
1446 }
1447
1448 if (!lyd_new_leaf(cont, NULL, "name", mod->name)) {
1449 return EXIT_FAILURE;
1450 }
1451 if (!lyd_new_leaf(cont, NULL, "revision", (mod->rev_size ? mod->rev[0].date : ""))) {
1452 return EXIT_FAILURE;
1453 }
Michal Vasko0c2215b2016-08-25 14:18:43 +02001454
1455 break;
Michal Vasko89563fc2016-07-28 16:19:35 +02001456 }
Michal Vasko209a6222015-10-16 09:51:07 +02001457 }
1458 }
1459 }
1460
1461 return EXIT_SUCCESS;
1462}
1463
1464static int
1465ylib_submodules(struct lyd_node *parent, struct lys_module *cur_mod)
1466{
1467 int i;
Radek Krejcia77904e2016-02-25 16:23:45 +01001468 char *str;
Radek Krejcid9723912016-09-16 17:06:06 +02001469 struct lyd_node *item;
Michal Vasko209a6222015-10-16 09:51:07 +02001470
Radek Krejcic071c542016-01-27 14:57:51 +01001471 for (i = 0; i < cur_mod->inc_size && cur_mod->inc[i].submodule; ++i) {
Radek Krejcid9723912016-09-16 17:06:06 +02001472 item = lyd_new(parent, NULL, "submodule");
Radek Krejci6e05cea2015-12-10 16:34:37 +01001473 if (!item) {
Michal Vasko209a6222015-10-16 09:51:07 +02001474 return EXIT_FAILURE;
1475 }
1476
Radek Krejci6e05cea2015-12-10 16:34:37 +01001477 if (!lyd_new_leaf(item, NULL, "name", cur_mod->inc[i].submodule->name)) {
Michal Vasko209a6222015-10-16 09:51:07 +02001478 return EXIT_FAILURE;
1479 }
Radek Krejci6e05cea2015-12-10 16:34:37 +01001480 if (!lyd_new_leaf(item, NULL, "revision", (cur_mod->inc[i].submodule->rev_size ?
Michal Vasko3e671b52015-10-23 16:23:15 +02001481 cur_mod->inc[i].submodule->rev[0].date : ""))) {
Michal Vasko209a6222015-10-16 09:51:07 +02001482 return EXIT_FAILURE;
1483 }
Radek Krejcia77904e2016-02-25 16:23:45 +01001484 if (cur_mod->inc[i].submodule->filepath) {
Radek Krejci95aa2012016-03-03 11:21:09 +01001485 if (asprintf(&str, "file://%s", cur_mod->inc[i].submodule->filepath) == -1) {
Radek Krejcia77904e2016-02-25 16:23:45 +01001486 LOGMEM;
1487 return EXIT_FAILURE;
Radek Krejci6e65af92016-03-07 12:48:19 +01001488 } else if (!lyd_new_leaf(item, NULL, "schema", str)) {
Radek Krejci19f9ede2016-02-25 16:29:21 +01001489 free(str);
Radek Krejcia77904e2016-02-25 16:23:45 +01001490 return EXIT_FAILURE;
1491 }
Radek Krejci19f9ede2016-02-25 16:29:21 +01001492 free(str);
Michal Vasko209a6222015-10-16 09:51:07 +02001493 }
1494 }
1495
1496 return EXIT_SUCCESS;
1497}
1498
1499API struct lyd_node *
1500ly_ctx_info(struct ly_ctx *ctx)
1501{
Radek Krejcidfb00d62017-09-06 09:39:35 +02001502 int i, bis = 0;
Michal Vasko209a6222015-10-16 09:51:07 +02001503 char id[8];
Radek Krejcia77904e2016-02-25 16:23:45 +01001504 char *str;
Michal Vasko1e62a092015-12-01 12:27:20 +01001505 const struct lys_module *mod;
Radek Krejcidaa547a2017-09-22 15:56:27 +02001506 struct lyd_node *root, *root_bis = NULL, *cont = NULL, *cont_bis = NULL;
Michal Vasko209a6222015-10-16 09:51:07 +02001507
Michal Vasko7eccc6c2016-03-24 14:56:33 +01001508 if (!ctx) {
1509 ly_errno = LY_EINVAL;
1510 return NULL;
1511 }
1512
Radek Krejcidfb00d62017-09-06 09:39:35 +02001513 mod = ly_ctx_get_module(ctx, "ietf-yang-library", NULL, 1);
Radek Krejcibd9e8d22016-02-03 14:11:48 +01001514 if (!mod || !mod->data) {
Radek Krejcidfb00d62017-09-06 09:39:35 +02001515 LOGERR(LY_EINVAL, "ietf-yang-library is not implemented.");
1516 return NULL;
1517 }
1518 if (mod->rev && !strcmp(mod->rev[0].date, "2016-06-21")) {
1519 bis = 0;
1520 } else if (mod->rev && !strcmp(mod->rev[0].date, IETF_YANG_LIB_REV)) {
1521 bis = 1;
1522 } else {
1523 LOGERR(LY_EINVAL, "Incompatible ietf-yang-library version in context.");
Michal Vasko209a6222015-10-16 09:51:07 +02001524 return NULL;
1525 }
1526
Radek Krejcibd9e8d22016-02-03 14:11:48 +01001527 root = lyd_new(NULL, mod, "modules-state");
Michal Vasko209a6222015-10-16 09:51:07 +02001528 if (!root) {
1529 return NULL;
1530 }
1531
Radek Krejcidfb00d62017-09-06 09:39:35 +02001532 if (bis) {
1533 root_bis = lyd_new(NULL, mod, "yang-library");
1534 if (!root_bis || !lyd_new(root_bis, mod, "modules") || !lyd_new(root_bis, mod, "module-sets")) {
1535 goto error;
1536 }
1537 }
1538
Michal Vasko209a6222015-10-16 09:51:07 +02001539 for (i = 0; i < ctx->models.used; ++i) {
Radek Krejci0ec51da2016-12-14 16:42:03 +01001540 if (ctx->models.list[i]->disabled) {
1541 /* skip the disabled modules */
1542 continue;
1543 }
1544
Radek Krejcidfb00d62017-09-06 09:39:35 +02001545 cont = lyd_new(root, mod, "module");
Michal Vasko209a6222015-10-16 09:51:07 +02001546 if (!cont) {
Radek Krejcidfb00d62017-09-06 09:39:35 +02001547 goto error;
1548 }
1549 if (bis) {
1550 if (!(cont_bis = lyd_new(root_bis->child, mod, "module"))) {
1551 goto error;
1552 }
1553
1554 /* id is present only in yang-library container */
1555 sprintf(id, "%d", i);
1556 if (!lyd_new_leaf(cont_bis, mod, "id", id)) {
1557 goto error;
1558 }
Michal Vasko209a6222015-10-16 09:51:07 +02001559 }
1560
Radek Krejcidfb00d62017-09-06 09:39:35 +02001561 /* name */
1562 if (!lyd_new_leaf(cont, mod, "name", ctx->models.list[i]->name)) {
1563 goto error;
Michal Vasko209a6222015-10-16 09:51:07 +02001564 }
Radek Krejcidfb00d62017-09-06 09:39:35 +02001565 if (bis && !lyd_new_leaf(cont_bis, mod, "name", ctx->models.list[i]->name)) {
1566 goto error;
1567 }
1568 /* revision */
1569 if (!lyd_new_leaf(cont, mod, "revision", (ctx->models.list[i]->rev_size ?
Michal Vasko209a6222015-10-16 09:51:07 +02001570 ctx->models.list[i]->rev[0].date : ""))) {
Radek Krejcidfb00d62017-09-06 09:39:35 +02001571 goto error;
Michal Vasko209a6222015-10-16 09:51:07 +02001572 }
Radek Krejcidfb00d62017-09-06 09:39:35 +02001573 if (bis && !lyd_new_leaf(cont_bis, mod, "revision", (ctx->models.list[i]->rev_size ?
1574 ctx->models.list[i]->rev[0].date : ""))) {
1575 goto error;
1576 }
1577 /* schema */
Radek Krejcia77904e2016-02-25 16:23:45 +01001578 if (ctx->models.list[i]->filepath) {
Radek Krejci15412ca2016-03-03 11:16:52 +01001579 if (asprintf(&str, "file://%s", ctx->models.list[i]->filepath) == -1) {
Radek Krejcia77904e2016-02-25 16:23:45 +01001580 LOGMEM;
Radek Krejcidfb00d62017-09-06 09:39:35 +02001581 goto error;
1582 }
1583 if (!lyd_new_leaf(cont, mod, "schema", str)) {
Radek Krejci19f9ede2016-02-25 16:29:21 +01001584 free(str);
Radek Krejcidfb00d62017-09-06 09:39:35 +02001585 goto error;
1586 }
1587 if (bis && !lyd_new_leaf(cont_bis, mod, "schema", str)) {
1588 free(str);
1589 goto error;
Radek Krejcia77904e2016-02-25 16:23:45 +01001590 }
Radek Krejci19f9ede2016-02-25 16:29:21 +01001591 free(str);
Michal Vasko209a6222015-10-16 09:51:07 +02001592 }
Radek Krejcidfb00d62017-09-06 09:39:35 +02001593 /* namespace */
1594 if (!lyd_new_leaf(cont, mod, "namespace", ctx->models.list[i]->ns)) {
1595 goto error;
Michal Vasko209a6222015-10-16 09:51:07 +02001596 }
Radek Krejcidfb00d62017-09-06 09:39:35 +02001597 if (bis && !lyd_new_leaf(cont_bis, mod, "namespace", ctx->models.list[i]->ns)) {
1598 goto error;
1599 }
1600 /* feature leaf-list */
Michal Vasko209a6222015-10-16 09:51:07 +02001601 if (ylib_feature(cont, ctx->models.list[i])) {
Radek Krejcidfb00d62017-09-06 09:39:35 +02001602 goto error;
Michal Vasko209a6222015-10-16 09:51:07 +02001603 }
Radek Krejcidfb00d62017-09-06 09:39:35 +02001604 if (bis && ylib_feature(cont_bis, ctx->models.list[i])) {
1605 goto error;
1606 }
1607 /* deviation list */
Michal Vaskoff006c12016-02-17 11:15:19 +01001608 if (ylib_deviation(cont, ctx->models.list[i])) {
Radek Krejcidfb00d62017-09-06 09:39:35 +02001609 goto error;
Michal Vasko209a6222015-10-16 09:51:07 +02001610 }
Radek Krejcidfb00d62017-09-06 09:39:35 +02001611 if (bis && ylib_deviation(cont_bis, ctx->models.list[i])) {
1612 goto error;
Michal Vasko209a6222015-10-16 09:51:07 +02001613 }
Radek Krejcidfb00d62017-09-06 09:39:35 +02001614 /* conformance-type */
1615 if (!lyd_new_leaf(cont, mod, "conformance-type",
1616 ctx->models.list[i]->implemented ? "implement" : "import")) {
1617 goto error;
Michal Vasko209a6222015-10-16 09:51:07 +02001618 }
Radek Krejcidfb00d62017-09-06 09:39:35 +02001619 if (bis && !lyd_new_leaf(cont_bis, mod, "conformance-type",
1620 ctx->models.list[i]->implemented ? "implement" : "import")) {
1621 goto error;
1622 }
1623 /* submodule list */
Michal Vasko209a6222015-10-16 09:51:07 +02001624 if (ylib_submodules(cont, ctx->models.list[i])) {
Radek Krejcidfb00d62017-09-06 09:39:35 +02001625 goto error;
1626 }
1627 if (bis && ylib_submodules(cont_bis, ctx->models.list[i])) {
1628 goto error;
1629 }
1630 }
1631
1632 if (bis) {
1633 /* module-sets - libyang currently has just one module set with all modules */
1634 if (!(cont_bis = lyd_new(root_bis->child->next, mod, "module-set"))) {
1635 goto error;
1636 }
1637 if (!lyd_new_leaf(cont_bis, mod, "id", "complete")) {
1638 goto error;
1639 }
1640 /* refer all modules */
1641 for (i = 0; i < ctx->models.used; ++i) {
1642 sprintf(id, "%d", i);
1643 if (!lyd_new_leaf(cont_bis, mod, "module", id)) {
1644 goto error;
1645 }
Michal Vasko209a6222015-10-16 09:51:07 +02001646 }
1647 }
1648
1649 sprintf(id, "%u", ctx->models.module_set_id);
Michal Vasko3e671b52015-10-23 16:23:15 +02001650 if (!lyd_new_leaf(root, mod, "module-set-id", id)) {
Radek Krejcidfb00d62017-09-06 09:39:35 +02001651 goto error;
1652 }
1653 if (bis && !lyd_new_leaf(root_bis, mod, "checksum", id)) {
1654 goto error;
1655 }
1656
1657 if (root_bis) {
1658 if (lyd_insert_sibling(&root_bis, root)) {
1659 goto error;
1660 }
1661 root = root_bis;
1662 root_bis = 0;
Michal Vasko209a6222015-10-16 09:51:07 +02001663 }
1664
Michal Vaskocdb90172016-09-13 09:34:36 +02001665 if (lyd_validate(&root, LYD_OPT_NOSIBLINGS, NULL)) {
Radek Krejcidfb00d62017-09-06 09:39:35 +02001666 goto error;
Michal Vasko209a6222015-10-16 09:51:07 +02001667 }
1668
1669 return root;
Radek Krejcidfb00d62017-09-06 09:39:35 +02001670
1671error:
1672 lyd_free_withsiblings(root);
1673 lyd_free_withsiblings(root_bis);
1674 return NULL;
Michal Vasko209a6222015-10-16 09:51:07 +02001675}
Michal Vaskob3744402017-08-03 14:23:58 +02001676
1677API const struct lys_node *
1678ly_ctx_get_node(struct ly_ctx *ctx, const struct lys_node *start, const char *nodeid, int output)
1679{
1680 const struct lys_node *node;
1681
Michal Vaskob3a6e482017-09-14 13:50:28 +02001682 if ((!ctx && !start) || !nodeid || ((nodeid[0] != '/') && !start)) {
Michal Vaskob3744402017-08-03 14:23:58 +02001683 ly_errno = LY_EINVAL;
1684 return NULL;
1685 }
1686
Michal Vaskob3a6e482017-09-14 13:50:28 +02001687 if (!ctx) {
1688 ctx = start->module->ctx;
1689 }
1690
Michal Vaskob3744402017-08-03 14:23:58 +02001691 /* sets error and everything */
1692 node = resolve_json_nodeid(nodeid, ctx, start, output);
1693
1694 return node;
1695}