blob: 805d1006df05abbf8583c58a192ced0e62cdb8d2 [file] [log] [blame]
Radek Krejcida04f4a2015-05-21 12:54:09 +02001/**
2 * @file context.c
3 * @author Radek Krejci <rkrejci@cesnet.cz>
4 * @brief context implementation for libyang
5 *
6 * Copyright (c) 2015 CESNET, z.s.p.o.
7 *
Radek Krejci54f6fb32016-02-24 12:56:39 +01008 * This source code is licensed under BSD 3-Clause License (the "License").
9 * You may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
Michal Vasko8de098c2016-02-26 10:00:25 +010011 *
Radek Krejci54f6fb32016-02-24 12:56:39 +010012 * https://opensource.org/licenses/BSD-3-Clause
Radek Krejcida04f4a2015-05-21 12:54:09 +020013 */
14
15#define _GNU_SOURCE
Radek Krejcicf748252017-09-04 11:11:14 +020016#include <pthread.h>
Radek Krejcifd4e6e32015-08-10 15:00:51 +020017#include <stddef.h>
Radek Krejcida04f4a2015-05-21 12:54:09 +020018#include <stdlib.h>
19#include <string.h>
20#include <sys/types.h>
21#include <sys/stat.h>
22#include <unistd.h>
23#include <errno.h>
24#include <fcntl.h>
25
26#include "common.h"
27#include "context.h"
Radek Krejci41912fe2015-10-22 10:22:12 +020028#include "dict_private.h"
Michal Vasko209a6222015-10-16 09:51:07 +020029#include "parser.h"
Radek Krejcibc9cf932015-07-30 11:09:39 +020030#include "tree_internal.h"
Radek Krejci83a4bac2017-02-07 15:53:04 +010031#include "resolve.h"
Radek Krejcida04f4a2015-05-21 12:54:09 +020032
Radek Krejci858ad952017-01-04 11:16:32 +010033/*
34 * counter for references to the extensions plugins (for the number of contexts)
35 * located in extensions.c
36 */
37extern unsigned int ext_plugins_ref;
38
Radek Krejci532e5e92017-02-22 12:59:24 +010039#define IETF_YANG_METADATA_PATH "../models/ietf-yang-metadata@2016-08-05.h"
40#define YANG_PATH "../models/yang@2017-02-20.h"
Michal Vasko8d054e42015-08-03 12:42:06 +020041#define IETF_INET_TYPES_PATH "../models/ietf-inet-types@2013-07-15.h"
Michal Vasko21181c42015-08-03 13:46:45 +020042#define IETF_YANG_TYPES_PATH "../models/ietf-yang-types@2013-07-15.h"
Radek Krejcid9723912016-09-16 17:06:06 +020043#define IETF_YANG_LIB_PATH "../models/ietf-yang-library@2016-06-21.h"
44#define IETF_YANG_LIB_REV "2016-06-21"
Michal Vasko8d054e42015-08-03 12:42:06 +020045
Radek Krejci532e5e92017-02-22 12:59:24 +010046#include IETF_YANG_METADATA_PATH
47#include YANG_PATH
Michal Vasko8d054e42015-08-03 12:42:06 +020048#include IETF_INET_TYPES_PATH
Michal Vasko21181c42015-08-03 13:46:45 +020049#include IETF_YANG_TYPES_PATH
Michal Vasko8d054e42015-08-03 12:42:06 +020050#include IETF_YANG_LIB_PATH
51
Radek Krejci03203412016-06-23 15:20:53 +020052static struct internal_modules_s {
53 const char *name;
54 const char *revision;
55 const char *data;
56 uint8_t implemented;
57 LYS_INFORMAT format;
Michal Vasko2d051a12017-04-21 09:28:57 +020058} internal_modules[LY_INTERNAL_MODULE_COUNT] = {
Radek Krejci532e5e92017-02-22 12:59:24 +010059 {"ietf-yang-metadata", "2016-08-05", (const char*)ietf_yang_metadata_2016_08_05_yin, 0, LYS_IN_YIN},
60 {"yang", "2017-02-20", (const char*)yang_2017_02_20_yin, 1, LYS_IN_YIN},
Radek Krejci03203412016-06-23 15:20:53 +020061 {"ietf-inet-types", "2013-07-15", (const char*)ietf_inet_types_2013_07_15_yin, 0, LYS_IN_YIN},
62 {"ietf-yang-types", "2013-07-15", (const char*)ietf_yang_types_2013_07_15_yin, 0, LYS_IN_YIN},
Radek Krejci06f8bb92017-08-02 15:36:25 +020063 /* ietf-yang-library is expected at (LY_INTERNAL_MODULE_COUNT - 1) position! */
Radek Krejcid9723912016-09-16 17:06:06 +020064 {"ietf-yang-library", "2016-06-21", (const char*)ietf_yang_library_2016_06_21_yin, 1, LYS_IN_YIN}
Radek Krejci03203412016-06-23 15:20:53 +020065};
66
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020067API struct ly_ctx *
68ly_ctx_new(const char *search_dir)
Radek Krejcida04f4a2015-05-21 12:54:09 +020069{
Radek Krejcia8d111f2017-05-31 13:57:37 +020070 struct ly_ctx *ctx = NULL;
Michal Vasko7d7de952016-05-02 17:13:14 +020071 struct lys_module *module;
Radek Krejcia8d111f2017-05-31 13:57:37 +020072 char *cwd = NULL;
Igor Ternovsky9a10e1a2017-09-11 12:53:04 +100073 char *search_dir_list;
74 char *sep, *dir;
Igor Ternovsky6e6543d2017-09-12 10:37:28 +100075 int rc = EXIT_SUCCESS;
Radek Krejci03203412016-06-23 15:20:53 +020076 int i;
Radek Krejcida04f4a2015-05-21 12:54:09 +020077
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020078 ctx = calloc(1, sizeof *ctx);
Radek Krejcia8d111f2017-05-31 13:57:37 +020079 LY_CHECK_ERR_RETURN(!ctx, LOGMEM, NULL);
Radek Krejcida04f4a2015-05-21 12:54:09 +020080
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020081 /* dictionary */
82 lydict_init(&ctx->dict);
Radek Krejcida04f4a2015-05-21 12:54:09 +020083
Radek Krejci858ad952017-01-04 11:16:32 +010084 /* plugins */
Radek Krejci858ad952017-01-04 11:16:32 +010085 lyext_load_plugins();
86
Radek Krejcicf748252017-09-04 11:11:14 +020087 /* initialize thread-specific key */
88 while ((i = pthread_key_create(&ctx->errlist_key, ly_err_free)) == EAGAIN);
89
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020090 /* models list */
91 ctx->models.list = calloc(16, sizeof *ctx->models.list);
Radek Krejcia8d111f2017-05-31 13:57:37 +020092 LY_CHECK_ERR_RETURN(!ctx->models.list, LOGMEM; free(ctx), NULL);
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) {
Igor Ternovsky9a10e1a2017-09-11 12:53:04 +100097 search_dir_list = strdup(search_dir);
98 LY_CHECK_ERR_GOTO(!search_dir_list, LOGMEM, error);
99
Igor Ternovsky6e6543d2017-09-12 10:37:28 +1000100 for (dir = search_dir_list; (sep = strchr(dir, ':')) != NULL && rc == EXIT_SUCCESS; dir = sep + 1) {
Igor Ternovsky9a10e1a2017-09-11 12:53:04 +1000101 *sep = 0;
Igor Ternovsky6e6543d2017-09-12 10:37:28 +1000102 rc = ly_ctx_set_searchdir(ctx, dir);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200103 }
Igor Ternovsky6e6543d2017-09-12 10:37:28 +1000104 if (*dir && rc == EXIT_SUCCESS) {
105 rc = ly_ctx_set_searchdir(ctx, dir);
Radek Krejci15412ca2016-03-03 11:16:52 +0100106 }
Igor Ternovsky9a10e1a2017-09-11 12:53:04 +1000107 free(search_dir_list);
Igor Ternovsky6e6543d2017-09-12 10:37:28 +1000108 /* If ly_ctx_set_searchdir() failed, the error is already logged. Just exit */
109 if (rc != EXIT_SUCCESS) {
110 goto error;
111 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200112 }
Michal Vasko14719b22015-08-03 12:47:55 +0200113 ctx->models.module_set_id = 1;
114
Radek Krejci03203412016-06-23 15:20:53 +0200115 /* load internal modules */
Michal Vasko2d051a12017-04-21 09:28:57 +0200116 for (i = 0; i < LY_INTERNAL_MODULE_COUNT; i++) {
Radek Krejci03203412016-06-23 15:20:53 +0200117 module = (struct lys_module *)lys_parse_mem(ctx, internal_modules[i].data, internal_modules[i].format);
118 if (!module) {
Radek Krejcia8d111f2017-05-31 13:57:37 +0200119 goto error;
Radek Krejci03203412016-06-23 15:20:53 +0200120 }
121 module->implemented = internal_modules[i].implemented;
Michal Vasko8d054e42015-08-03 12:42:06 +0200122 }
Radek Krejcida04f4a2015-05-21 12:54:09 +0200123
Radek Krejcia8d111f2017-05-31 13:57:37 +0200124 /* cleanup */
125 free(cwd);
126
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200127 return ctx;
Radek Krejcia8d111f2017-05-31 13:57:37 +0200128
129error:
130 free(cwd);
131 ly_ctx_destroy(ctx, NULL);
132 return NULL;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200133}
134
Radek Krejci69333c92017-03-17 16:14:43 +0100135static struct ly_ctx *
136ly_ctx_new_yl_common(const char *search_dir, const char *input, LYD_FORMAT format,
137 struct lyd_node* (*parser_func)(struct ly_ctx*, const char*, LYD_FORMAT, int,...))
138{
139 unsigned int u;
140 struct lyd_node *module, *node;
141 const char *name, *revision;
Radek Krejci5cb217d2017-03-25 16:07:52 -0500142 struct ly_set features = {0, 0, {NULL}};
Radek Krejci69333c92017-03-17 16:14:43 +0100143 const struct lys_module *mod;
144 struct lyd_node *yltree = NULL;
145 struct ly_ctx *ctx = NULL;
146
147 /* create empty (with internal modules including ietf-yang-library) context */
148 ctx = ly_ctx_new(search_dir);
149 if (!ctx) {
150 goto error;
151 }
152
153 /* parse yang library data tree */
154 yltree = parser_func(ctx, input, format, LYD_OPT_DATA, NULL);
155 if (!yltree) {
156 goto error;
157 }
158
159 /* process the data tree */
160 LY_TREE_FOR(yltree->child, module) {
161 if (module->schema->nodetype == LYS_LEAF) {
162 /* module-set-id - ignore it */
163 continue;
164 }
165
166 /* initiate */
167 name = NULL;
168 revision = NULL;
169 ly_set_clean(&features);
170
171 LY_TREE_FOR(module->child, node) {
172 if (!strcmp(node->schema->name, "name")) {
173 name = ((struct lyd_node_leaf_list*)node)->value_str;
174 } else if (!strcmp(node->schema->name, "revision")) {
175 revision = ((struct lyd_node_leaf_list*)node)->value_str;
176 } else if (!strcmp(node->schema->name, "feature")) {
177 ly_set_add(&features, node, LY_SET_OPT_USEASLIST);
178 } else if (!strcmp(node->schema->name, "conformance-type") &&
179 ((struct lyd_node_leaf_list*)node)->value.enm->value) {
180 /* imported module - skip it, it will be loaded as a side effect
181 * of loading another module */
182 goto next_module;
183 }
184 }
185
186 /* use the gathered data to load the module */
187 mod = ly_ctx_load_module(ctx, name, revision);
188 if (!mod) {
189 LOGERR(LY_EINVAL, "Unable to load module specified by yang library data.");
190 goto error;
191 }
192
193 /* set features */
194 for (u = 0; u < features.number; u++) {
195 lys_features_enable(mod, ((struct lyd_node_leaf_list*)features.set.d[u])->value_str);
196 }
197
198next_module:;
199 }
200
201 if (0) {
202 /* skip context destroy in case of success */
203error:
204 ly_ctx_destroy(ctx, NULL);
205 ctx = NULL;
206 }
207
208 /* cleanup */
209 if (yltree) {
210 /* yang library data tree */
211 lyd_free_withsiblings(yltree);
212 }
213
214 return ctx;
215}
216
217API struct ly_ctx *
218ly_ctx_new_ylpath(const char *search_dir, const char *path, LYD_FORMAT format)
219{
220 return ly_ctx_new_yl_common(search_dir, path, format, lyd_parse_path);
221}
222
223API struct ly_ctx *
224ly_ctx_new_ylmem(const char *search_dir, const char *data, LYD_FORMAT format)
225{
226 return ly_ctx_new_yl_common(search_dir, data, format, lyd_parse_mem);
227}
228
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200229API void
Radek Krejci819dd4b2017-03-07 15:35:48 +0100230ly_ctx_set_allimplemented(struct ly_ctx *ctx)
231{
232 if (!ctx) {
233 return;
234 }
235
236 ctx->models.flags |= LY_CTX_ALLIMPLEMENTED;
237}
238
239API void
240ly_ctx_unset_allimplemented(struct ly_ctx *ctx)
241{
242 if (!ctx) {
243 return;
244 }
245
246 ctx->models.flags &= ~LY_CTX_ALLIMPLEMENTED;
247}
248
Igor Ternovsky6e6543d2017-09-12 10:37:28 +1000249API int
Michal Vasko60ba9a62015-07-03 14:42:31 +0200250ly_ctx_set_searchdir(struct ly_ctx *ctx, const char *search_dir)
251{
Radek Krejcia62a9d12017-08-09 12:37:51 +0200252 char *cwd = NULL, *new = NULL;
Radek Krejcida9f8392017-03-25 19:40:56 -0500253 int index = 0;
254 void *r;
Igor Ternovsky6e6543d2017-09-12 10:37:28 +1000255 int rc = EXIT_FAILURE;
Michal Vasko60ba9a62015-07-03 14:42:31 +0200256
257 if (!ctx) {
Radek Krejci961d96f2017-09-12 10:31:17 +0200258 LOGERR(LY_EINVAL, "%s: Invalid ctx parameter", __func__);
Igor Ternovsky6e6543d2017-09-12 10:37:28 +1000259 return EXIT_FAILURE;
Michal Vasko60ba9a62015-07-03 14:42:31 +0200260 }
261
262 if (search_dir) {
263 cwd = get_current_dir_name();
264 if (chdir(search_dir)) {
265 LOGERR(LY_ESYS, "Unable to use search directory \"%s\" (%s)",
266 search_dir, strerror(errno));
Radek Krejcia8d111f2017-05-31 13:57:37 +0200267 goto cleanup;
Michal Vasko60ba9a62015-07-03 14:42:31 +0200268 }
Radek Krejcida9f8392017-03-25 19:40:56 -0500269
Radek Krejci426ea2b2017-06-13 12:41:51 +0200270 new = get_current_dir_name();
Radek Krejcida9f8392017-03-25 19:40:56 -0500271 if (!ctx->models.search_paths) {
272 ctx->models.search_paths = malloc(2 * sizeof *ctx->models.search_paths);
Radek Krejcia8d111f2017-05-31 13:57:37 +0200273 LY_CHECK_ERR_GOTO(!ctx->models.search_paths, LOGMEM, cleanup);
Radek Krejcida9f8392017-03-25 19:40:56 -0500274 index = 0;
275 } else {
Radek Krejci426ea2b2017-06-13 12:41:51 +0200276 for (index = 0; ctx->models.search_paths[index]; index++) {
277 /* check for duplicities */
278 if (!strcmp(new, ctx->models.search_paths[index])) {
279 /* path is already present */
Radek Krejci426ea2b2017-06-13 12:41:51 +0200280 goto success;
281 }
282 }
Radek Krejcida9f8392017-03-25 19:40:56 -0500283 r = realloc(ctx->models.search_paths, (index + 2) * sizeof *ctx->models.search_paths);
Radek Krejcia8d111f2017-05-31 13:57:37 +0200284 LY_CHECK_ERR_GOTO(!r, LOGMEM, cleanup);
Radek Krejcida9f8392017-03-25 19:40:56 -0500285 ctx->models.search_paths = r;
286 }
Radek Krejci426ea2b2017-06-13 12:41:51 +0200287 ctx->models.search_paths[index] = new;
Radek Krejcia62a9d12017-08-09 12:37:51 +0200288 new = NULL;
Radek Krejcida9f8392017-03-25 19:40:56 -0500289 ctx->models.search_paths[index + 1] = NULL;
Michal Vasko3eff9322015-11-10 11:02:30 +0100290
Radek Krejci426ea2b2017-06-13 12:41:51 +0200291success:
Radek Krejci15412ca2016-03-03 11:16:52 +0100292 if (chdir(cwd)) {
293 LOGWRN("Unable to return back to working directory \"%s\" (%s)",
294 cwd, strerror(errno));
295 }
Igor Ternovsky6e6543d2017-09-12 10:37:28 +1000296 rc = EXIT_SUCCESS;
Michal Vasko60ba9a62015-07-03 14:42:31 +0200297 }
Radek Krejcia8d111f2017-05-31 13:57:37 +0200298
299cleanup:
300 free(cwd);
Radek Krejcia62a9d12017-08-09 12:37:51 +0200301 free(new);
Igor Ternovsky6e6543d2017-09-12 10:37:28 +1000302 return rc;
Michal Vasko60ba9a62015-07-03 14:42:31 +0200303}
304
Radek Krejci426ea2b2017-06-13 12:41:51 +0200305API const char * const *
306ly_ctx_get_searchdirs(const struct ly_ctx *ctx)
Radek Krejci5a797572015-10-21 15:45:45 +0200307{
Radek Krejciee554172016-12-14 10:29:06 +0100308 if (!ctx) {
Radek Krejci961d96f2017-09-12 10:31:17 +0200309 LOGERR(LY_EINVAL, "%s: Invalid ctx parameter", __func__);
Radek Krejciee554172016-12-14 10:29:06 +0100310 return NULL;
311 }
Radek Krejci426ea2b2017-06-13 12:41:51 +0200312 return (const char * const *)ctx->models.search_paths;
Radek Krejcida9f8392017-03-25 19:40:56 -0500313}
314
315API void
Radek Krejcidb4e9ff2017-06-13 16:26:14 +0200316ly_ctx_unset_searchdirs(struct ly_ctx *ctx, int index)
Radek Krejcida9f8392017-03-25 19:40:56 -0500317{
318 int i;
319
320 if (!ctx->models.search_paths) {
321 return;
322 }
323
324 for (i = 0; ctx->models.search_paths[i]; i++) {
Radek Krejcidb4e9ff2017-06-13 16:26:14 +0200325 if (index < 0 || index == i) {
326 free(ctx->models.search_paths[i]);
327 ctx->models.search_paths[i] = NULL;
328 } else if (i > index) {
329 ctx->models.search_paths[i - 1] = ctx->models.search_paths[i];
330 ctx->models.search_paths[i] = NULL;
331 }
Radek Krejcida9f8392017-03-25 19:40:56 -0500332 }
Radek Krejcidb4e9ff2017-06-13 16:26:14 +0200333 if (index < 0 || !ctx->models.search_paths[0]) {
334 free(ctx->models.search_paths);
335 ctx->models.search_paths = NULL;
336 }
Radek Krejci5a797572015-10-21 15:45:45 +0200337}
338
Michal Vasko60ba9a62015-07-03 14:42:31 +0200339API void
Radek Krejcifa0b5e02016-02-04 13:57:03 +0100340ly_ctx_destroy(struct ly_ctx *ctx, void (*private_destructor)(const struct lys_node *node, void *priv))
Radek Krejcida04f4a2015-05-21 12:54:09 +0200341{
Radek Krejcida9f8392017-03-25 19:40:56 -0500342 int i;
343
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200344 if (!ctx) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200345 return;
346 }
Radek Krejcida04f4a2015-05-21 12:54:09 +0200347
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200348 /* models list */
Radek Krejcic436a232017-02-08 14:43:11 +0100349 for (; ctx->models.used > 0; ctx->models.used--) {
Radek Krejcifc8411a2017-02-03 10:26:05 +0100350 /* remove the applied deviations and augments */
Radek Krejcic436a232017-02-08 14:43:11 +0100351 lys_sub_module_remove_devs_augs(ctx->models.list[ctx->models.used - 1]);
Radek Krejcifc8411a2017-02-03 10:26:05 +0100352 /* remove the module */
Radek Krejcic436a232017-02-08 14:43:11 +0100353 lys_free(ctx->models.list[ctx->models.used - 1], private_destructor, 0);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200354 }
Radek Krejcida9f8392017-03-25 19:40:56 -0500355 if (ctx->models.search_paths) {
356 for(i = 0; ctx->models.search_paths[i]; i++) {
357 free(ctx->models.search_paths[i]);
358 }
359 free(ctx->models.search_paths);
360 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200361 free(ctx->models.list);
Radek Krejcida04f4a2015-05-21 12:54:09 +0200362
Radek Krejcicf748252017-09-04 11:11:14 +0200363 /* clean the error list */
364 ly_err_clean(ctx, 0);
365 pthread_key_delete(ctx->errlist_key);
366
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200367 /* dictionary */
368 lydict_clean(&ctx->dict);
Radek Krejcida04f4a2015-05-21 12:54:09 +0200369
Radek Krejci858ad952017-01-04 11:16:32 +0100370 /* plugins - will be removed only if this is the last context */
371 ext_plugins_ref--;
372 lyext_clean_plugins();
373
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200374 free(ctx);
Radek Krejcida04f4a2015-05-21 12:54:09 +0200375}
376
Michal Vasko1e62a092015-12-01 12:27:20 +0100377API const struct lys_submodule *
Radek Krejci62f0da72016-03-07 11:35:43 +0100378ly_ctx_get_submodule2(const struct lys_module *main_module, const char *submodule)
379{
Radek Krejcid4c1d0f2017-01-19 16:11:38 +0100380 const struct lys_submodule *result;
Radek Krejci62f0da72016-03-07 11:35:43 +0100381 int i;
382
383 if (!main_module || !submodule) {
384 ly_errno = LY_EINVAL;
385 return NULL;
386 }
387
388 /* search in submodules list */
389 for (i = 0; i < main_module->inc_size; i++) {
390 result = main_module->inc[i].submodule;
Radek Krejcid4c1d0f2017-01-19 16:11:38 +0100391 if (ly_strequal(submodule, result->name, 0)) {
Radek Krejci62f0da72016-03-07 11:35:43 +0100392 return result;
393 }
Radek Krejcid4c1d0f2017-01-19 16:11:38 +0100394
395 /* in YANG 1.1 all the submodules must be included in the main module, so we are done.
396 * YANG 1.0 allows (is unclear about denying it) to include a submodule only in another submodule
397 * but when libyang parses such a module it adds the include into the main module so we are also done.
398 */
Radek Krejci62f0da72016-03-07 11:35:43 +0100399 }
400
Radek Krejcid4c1d0f2017-01-19 16:11:38 +0100401
Radek Krejci62f0da72016-03-07 11:35:43 +0100402 return NULL;
403}
404
405API const struct lys_submodule *
Michal Vaskof6d94c62016-04-05 11:21:54 +0200406ly_ctx_get_submodule(const struct ly_ctx *ctx, const char *module, const char *revision, const char *submodule,
407 const char *sub_revision)
Radek Krejciefaeba32015-05-27 14:30:57 +0200408{
Radek Krejcie7973552016-03-07 08:12:01 +0100409 const struct lys_module *mainmod;
Michal Vaskof6d94c62016-04-05 11:21:54 +0200410 const struct lys_submodule *ret = NULL, *submod;
411 uint32_t idx = 0;
Radek Krejciefaeba32015-05-27 14:30:57 +0200412
Michal Vaskof6d94c62016-04-05 11:21:54 +0200413 if (!ctx || !submodule || (revision && !module)) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200414 ly_errno = LY_EINVAL;
415 return NULL;
416 }
Radek Krejciefaeba32015-05-27 14:30:57 +0200417
Michal Vaskof6d94c62016-04-05 11:21:54 +0200418 while ((mainmod = ly_ctx_get_module_iter(ctx, &idx))) {
419 if (module && strcmp(mainmod->name, module)) {
420 /* main module name does not match */
421 continue;
422 }
423
424 if (revision && (!mainmod->rev || strcmp(revision, mainmod->rev[0].date))) {
425 /* main module revision does not match */
426 continue;
427 }
428
429 submod = ly_ctx_get_submodule2(mainmod, submodule);
430 if (!submod) {
431 continue;
432 }
433
434 if (!sub_revision) {
435 /* store only if newer */
436 if (ret) {
437 if (submod->rev && (!ret->rev || (strcmp(submod->rev[0].date, ret->rev[0].date) > 0))) {
438 ret = submod;
439 }
440 } else {
441 ret = submod;
442 }
443 } else {
444 /* store only if revision matches, we are done if it does */
445 if (!submod->rev) {
446 continue;
447 } else if (!strcmp(sub_revision, submod->rev[0].date)) {
448 ret = submod;
449 break;
450 }
451 }
Radek Krejcia7533f22016-03-07 07:37:45 +0100452 }
Radek Krejcic071c542016-01-27 14:57:51 +0100453
Michal Vaskof6d94c62016-04-05 11:21:54 +0200454 return ret;
Radek Krejciefaeba32015-05-27 14:30:57 +0200455}
456
Michal Vasko1e62a092015-12-01 12:27:20 +0100457static const struct lys_module *
Radek Krejci0ec51da2016-12-14 16:42:03 +0100458ly_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 +0200459{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200460 int i;
Radek Krejcib8048692015-08-05 13:36:34 +0200461 struct lys_module *result = NULL;
Radek Krejciefaeba32015-05-27 14:30:57 +0200462
Radek Krejcifd4e6e32015-08-10 15:00:51 +0200463 if (!ctx || !key) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200464 ly_errno = LY_EINVAL;
465 return NULL;
466 }
Radek Krejciefaeba32015-05-27 14:30:57 +0200467
Radek Krejcidce51452015-06-16 15:20:08 +0200468 for (i = 0; i < ctx->models.used; i++) {
Radek Krejci0ec51da2016-12-14 16:42:03 +0100469 if (!with_disabled && ctx->models.list[i]->disabled) {
470 /* skip the disabled modules */
471 continue;
472 }
Radek Krejcifd4e6e32015-08-10 15:00:51 +0200473 /* use offset to get address of the pointer to string (char**), remember that offset is in
474 * bytes, so we have to cast the pointer to the module to (char*), finally, we want to have
475 * string not the pointer to string
476 */
477 if (!ctx->models.list[i] || strcmp(key, *(char**)(((char*)ctx->models.list[i]) + offset))) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200478 continue;
479 }
Radek Krejciefaeba32015-05-27 14:30:57 +0200480
Radek Krejcif647e612015-07-30 11:36:07 +0200481 if (!revision) {
482 /* compare revisons and remember the newest one */
483 if (result) {
484 if (!ctx->models.list[i]->rev_size) {
485 /* the current have no revision, keep the previous with some revision */
486 continue;
487 }
488 if (result->rev_size && strcmp(ctx->models.list[i]->rev[0].date, result->rev[0].date) < 0) {
489 /* the previous found matching module has a newer revision */
490 continue;
491 }
492 }
493
494 /* remember the current match and search for newer version */
495 result = ctx->models.list[i];
496 } else {
497 if (ctx->models.list[i]->rev_size && !strcmp(revision, ctx->models.list[i]->rev[0].date)) {
498 /* matching revision */
Michal Vasko97586502015-08-12 14:32:18 +0200499 result = ctx->models.list[i];
500 break;
Radek Krejcif647e612015-07-30 11:36:07 +0200501 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200502 }
503 }
Radek Krejciefaeba32015-05-27 14:30:57 +0200504
Radek Krejcif647e612015-07-30 11:36:07 +0200505 return result;
Radek Krejcifd4e6e32015-08-10 15:00:51 +0200506
507}
508
Michal Vasko1e62a092015-12-01 12:27:20 +0100509API const struct lys_module *
510ly_ctx_get_module_by_ns(const struct ly_ctx *ctx, const char *ns, const char *revision)
Radek Krejcifd4e6e32015-08-10 15:00:51 +0200511{
Radek Krejci0ec51da2016-12-14 16:42:03 +0100512 return ly_ctx_get_module_by(ctx, ns, offsetof(struct lys_module, ns), revision, 0);
Radek Krejcifd4e6e32015-08-10 15:00:51 +0200513}
514
Michal Vasko1e62a092015-12-01 12:27:20 +0100515API const struct lys_module *
516ly_ctx_get_module(const struct ly_ctx *ctx, const char *name, const char *revision)
Radek Krejcifd4e6e32015-08-10 15:00:51 +0200517{
Radek Krejci0ec51da2016-12-14 16:42:03 +0100518 return ly_ctx_get_module_by(ctx, name, offsetof(struct lys_module, name), revision, 0);
Radek Krejcida04f4a2015-05-21 12:54:09 +0200519}
Michal Vasko3ec07dc2015-06-30 15:51:30 +0200520
Radek Krejci21601a32016-03-07 11:39:27 +0100521API const struct lys_module *
522ly_ctx_get_module_older(const struct ly_ctx *ctx, const struct lys_module *module)
523{
524 int i;
525 const struct lys_module *result = NULL, *iter;
526
527 if (!ctx || !module || !module->rev_size) {
528 ly_errno = LY_EINVAL;
529 return NULL;
530 }
531
532
533 for (i = 0; i < ctx->models.used; i++) {
534 iter = ctx->models.list[i];
Radek Krejci0ec51da2016-12-14 16:42:03 +0100535 if (iter->disabled) {
536 /* skip the disabled modules */
537 continue;
538 }
Radek Krejci21601a32016-03-07 11:39:27 +0100539 if (iter == module || !iter->rev_size) {
540 /* iter is the module itself or iter has no revision */
541 continue;
542 }
543 if (!ly_strequal(module->name, iter->name, 0)) {
544 /* different module */
545 continue;
546 }
547 if (strcmp(iter->rev[0].date, module->rev[0].date) < 0) {
548 /* iter is older than module */
549 if (result) {
550 if (strcmp(iter->rev[0].date, result->rev[0].date) > 0) {
551 /* iter is newer than current result */
552 result = iter;
553 }
554 } else {
555 result = iter;
556 }
557 }
558 }
559
560 return result;
561}
562
Michal Vasko99b0aad2015-12-01 12:28:51 +0100563API void
Michal Vaskoca28aab2017-01-13 13:50:12 +0100564ly_ctx_set_module_imp_clb(struct ly_ctx *ctx, ly_module_imp_clb clb, void *user_data)
Michal Vasko82465962015-11-10 11:03:11 +0100565{
Michal Vaskoad9f92a2017-04-06 09:49:07 +0200566 if (!ctx) {
567 ly_errno = LY_EINVAL;
568 return;
569 }
570
Michal Vaskof53187d2017-01-13 13:23:14 +0100571 ctx->imp_clb = clb;
572 ctx->imp_clb_data = user_data;
Michal Vasko99b0aad2015-12-01 12:28:51 +0100573}
574
Michal Vaskof53187d2017-01-13 13:23:14 +0100575API ly_module_imp_clb
Michal Vaskoca28aab2017-01-13 13:50:12 +0100576ly_ctx_get_module_imp_clb(const struct ly_ctx *ctx, void **user_data)
Michal Vasko99b0aad2015-12-01 12:28:51 +0100577{
Radek Krejciee554172016-12-14 10:29:06 +0100578 if (!ctx) {
579 ly_errno = LY_EINVAL;
580 return NULL;
581 }
582
Michal Vasko99b0aad2015-12-01 12:28:51 +0100583 if (user_data) {
Michal Vaskof53187d2017-01-13 13:23:14 +0100584 *user_data = ctx->imp_clb_data;
Michal Vasko99b0aad2015-12-01 12:28:51 +0100585 }
Michal Vaskof53187d2017-01-13 13:23:14 +0100586 return ctx->imp_clb;
587}
588
589API void
Michal Vaskoca28aab2017-01-13 13:50:12 +0100590ly_ctx_set_module_data_clb(struct ly_ctx *ctx, ly_module_data_clb clb, void *user_data)
Michal Vaskof53187d2017-01-13 13:23:14 +0100591{
Michal Vaskoad9f92a2017-04-06 09:49:07 +0200592 if (!ctx) {
593 ly_errno = LY_EINVAL;
594 return;
595 }
596
Michal Vaskof53187d2017-01-13 13:23:14 +0100597 ctx->data_clb = clb;
598 ctx->data_clb_data = user_data;
599}
600
601API ly_module_data_clb
Michal Vaskoca28aab2017-01-13 13:50:12 +0100602ly_ctx_get_module_data_clb(const struct ly_ctx *ctx, void **user_data)
Michal Vaskof53187d2017-01-13 13:23:14 +0100603{
Michal Vaskoad9f92a2017-04-06 09:49:07 +0200604 if (!ctx) {
605 ly_errno = LY_EINVAL;
606 return NULL;
607 }
608
Michal Vaskof53187d2017-01-13 13:23:14 +0100609 if (user_data) {
610 *user_data = ctx->data_clb_data;
611 }
612 return ctx->data_clb;
Michal Vasko99b0aad2015-12-01 12:28:51 +0100613}
614
Radek Krejcibf4e4652016-10-21 15:44:13 +0200615const struct lys_module *
Michal Vasko84475152016-07-25 16:16:25 +0200616ly_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 +0200617 int implement, struct unres_schema *unres)
Michal Vasko99b0aad2015-12-01 12:28:51 +0100618{
Radek Krejcibf4e4652016-10-21 15:44:13 +0200619 const struct lys_module *mod;
Michal Vasko99b0aad2015-12-01 12:28:51 +0100620 char *module_data;
Radek Krejci03203412016-06-23 15:20:53 +0200621 int i;
Michal Vaskod3e975b2016-03-03 15:40:21 +0100622 void (*module_data_free)(void *module_data) = NULL;
Michal Vasko99b0aad2015-12-01 12:28:51 +0100623 LYS_INFORMAT format = LYS_IN_UNKNOWN;
Michal Vasko82465962015-11-10 11:03:11 +0100624
Michal Vasko84475152016-07-25 16:16:25 +0200625 if (!module) {
Radek Krejcibf4e4652016-10-21 15:44:13 +0200626 /* exception for internal modules */
Michal Vasko2d051a12017-04-21 09:28:57 +0200627 for (i = 0; i < LY_INTERNAL_MODULE_COUNT; i++) {
Michal Vasko84475152016-07-25 16:16:25 +0200628 if (ly_strequal(name, internal_modules[i].name, 0)) {
629 if (!revision || ly_strequal(revision, internal_modules[i].revision, 0)) {
630 /* return internal module */
631 return (struct lys_module *)ly_ctx_get_module(ctx, name, revision);
632 }
Radek Krejci03203412016-06-23 15:20:53 +0200633 }
634 }
Radek Krejcibf4e4652016-10-21 15:44:13 +0200635 if (revision) {
Radek Krejci0ec51da2016-12-14 16:42:03 +0100636 /* try to get the schema with the specific revision from the context,
637 * include the disabled modules in the search to avoid their duplication,
638 * they are enabled by the subsequent call to lys_set_implemented() */
Michal Vasko2d051a12017-04-21 09:28:57 +0200639 for (i = LY_INTERNAL_MODULE_COUNT, mod = NULL; i < ctx->models.used; i++) {
Radek Krejci0ec51da2016-12-14 16:42:03 +0100640 mod = ctx->models.list[i]; /* shortcut */
641 if (ly_strequal(name, mod->name, 0) && mod->rev_size && !strcmp(revision, mod->rev[0].date)) {
642 break;
643 }
644 mod = NULL;
645 }
Radek Krejcibf4e4652016-10-21 15:44:13 +0200646 if (mod) {
647 /* we get such a module, make it implemented */
648 if (lys_set_implemented(mod)) {
649 /* the schema cannot be implemented */
650 mod = NULL;
651 }
652 return mod;
653 }
654 }
Radek Krejci03203412016-06-23 15:20:53 +0200655 }
656
Michal Vaskof53187d2017-01-13 13:23:14 +0100657 if (ctx->imp_clb) {
Michal Vasko84475152016-07-25 16:16:25 +0200658 if (module) {
659 mod = lys_main_module(module);
Michal Vaskof53187d2017-01-13 13:23:14 +0100660 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 +0200661 } else {
Michal Vaskof53187d2017-01-13 13:23:14 +0100662 module_data = ctx->imp_clb(name, revision, NULL, NULL, ctx->imp_clb_data, &format, &module_data_free);
Michal Vasko84475152016-07-25 16:16:25 +0200663 }
Michal Vasko99b0aad2015-12-01 12:28:51 +0100664 if (!module_data) {
Radek Krejcibf4e4652016-10-21 15:44:13 +0200665 if (module || revision) {
666 /* we already know that the specified revision is not present in context, and we have no other
667 * option in case of submodules */
668 LOGERR(LY_ESYS, "User module retrieval callback failed!");
669 return NULL;
670 } else {
671 /* get the newest revision from the context */
Radek Krejci0ec51da2016-12-14 16:42:03 +0100672 mod = ly_ctx_get_module_by(ctx, name, offsetof(struct lys_module, name), revision, 1);
673 if (mod && mod->disabled) {
674 /* enable the required module */
675 lys_set_enabled(mod);
676 }
677 return mod;
Radek Krejcibf4e4652016-10-21 15:44:13 +0200678 }
Michal Vasko82465962015-11-10 11:03:11 +0100679 }
Michal Vasko84475152016-07-25 16:16:25 +0200680
681 if (module) {
Michal Vasko5b998712017-01-26 10:34:06 +0100682 mod = (struct lys_module *)lys_sub_parse_mem(module, module_data, format, unres);
Michal Vasko84475152016-07-25 16:16:25 +0200683 } else {
Michal Vasko29245662017-04-18 15:56:31 +0200684 mod = (struct lys_module *)lys_parse_mem_(ctx, module_data, format, 0, implement);
Michal Vasko84475152016-07-25 16:16:25 +0200685 }
686
Michal Vasko99b0aad2015-12-01 12:28:51 +0100687 if (module_data_free) {
688 module_data_free(module_data);
Michal Vasko82465962015-11-10 11:03:11 +0100689 }
Michal Vasko99b0aad2015-12-01 12:28:51 +0100690 } else {
Michal Vasko58e5f3e2016-07-28 11:06:34 +0200691 mod = lyp_search_file(ctx, module, name, revision, implement, unres);
Michal Vasko82465962015-11-10 11:03:11 +0100692 }
693
Michal Vasko84475152016-07-25 16:16:25 +0200694 return mod;
695}
696
697API const struct lys_module *
698ly_ctx_load_module(struct ly_ctx *ctx, const char *name, const char *revision)
699{
700 if (!ctx || !name) {
701 ly_errno = LY_EINVAL;
702 return NULL;
703 }
704
Radek Krejci05f15982017-06-13 15:26:10 +0200705 return ly_ctx_load_sub_module(ctx, NULL, name, revision && revision[0] ? revision : NULL, 1, NULL);
Michal Vasko82465962015-11-10 11:03:11 +0100706}
707
Radek Krejci85a54be2016-10-20 12:39:56 +0200708/*
709 * mods - set of removed modules, if NULL all modules are supposed to be removed so any backlink is invalid
710 */
Michal Vasko4be5fa22017-02-07 10:12:32 +0100711static void
712ctx_modules_undo_backlinks(struct ly_ctx *ctx, struct ly_set *mods)
Radek Krejci85a54be2016-10-20 12:39:56 +0200713{
714 int o;
715 uint8_t j;
716 unsigned int u, v;
717 struct lys_module *mod;
718 struct lys_node *elem, *next;
719 struct lys_node_leaf *leaf;
720
721 /* maintain backlinks (start with internal ietf-yang-library which have leafs as possible targets of leafrefs */
Michal Vasko2d051a12017-04-21 09:28:57 +0200722 for (o = LY_INTERNAL_MODULE_COUNT - 1; o < ctx->models.used; o++) {
Radek Krejci85a54be2016-10-20 12:39:56 +0200723 mod = ctx->models.list[o]; /* shortcut */
724
725 /* 1) features */
726 for (j = 0; j < mod->features_size; j++) {
727 if (!mod->features[j].depfeatures) {
728 continue;
729 }
730 for (v = 0; v < mod->features[j].depfeatures->number; v++) {
731 if (!mods || ly_set_contains(mods, ((struct lys_feature *)mod->features[j].depfeatures->set.g[v])->module) != -1) {
732 /* depending feature is in module to remove */
733 ly_set_rm_index(mod->features[j].depfeatures, v);
734 v--;
735 }
736 }
737 if (!mod->features[j].depfeatures->number) {
738 /* all backlinks removed */
739 ly_set_free(mod->features[j].depfeatures);
740 mod->features[j].depfeatures = NULL;
741 }
742 }
Michal Vasko4be5fa22017-02-07 10:12:32 +0100743
744 /* 2) identities */
Radek Krejci85a54be2016-10-20 12:39:56 +0200745 for (u = 0; u < mod->ident_size; u++) {
746 if (!mod->ident[u].der) {
747 continue;
748 }
749 for (v = 0; v < mod->ident[u].der->number; v++) {
750 if (!mods || ly_set_contains(mods, ((struct lys_ident *)mod->ident[u].der->set.g[v])->module) != -1) {
751 /* derived identity is in module to remove */
752 ly_set_rm_index(mod->ident[u].der, v);
753 v--;
754 }
755 }
756 if (!mod->ident[u].der->number) {
757 /* all backlinks removed */
758 ly_set_free(mod->ident[u].der);
759 mod->ident[u].der = NULL;
760 }
761 }
762
Michal Vasko4be5fa22017-02-07 10:12:32 +0100763 /* 3) leafrefs */
Radek Krejci85a54be2016-10-20 12:39:56 +0200764 for (elem = next = mod->data; elem; elem = next) {
765 if (elem->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
766 leaf = (struct lys_node_leaf *)elem; /* shortcut */
767 if (leaf->backlinks) {
768 if (!mods) {
769 /* remove all backlinks */
770 ly_set_free(leaf->backlinks);
771 leaf->backlinks = NULL;
772 } else {
773 for (v = 0; v < leaf->backlinks->number; v++) {
774 if (ly_set_contains(mods, leaf->backlinks->set.s[v]->module) != -1) {
775 /* derived identity is in module to remove */
776 ly_set_rm_index(leaf->backlinks, v);
777 v--;
778 }
779 }
780 if (!leaf->backlinks->number) {
781 /* all backlinks removed */
782 ly_set_free(leaf->backlinks);
783 leaf->backlinks = NULL;
784 }
785 }
786 }
787 }
788
789 /* select next element to process */
790 next = elem->child;
791 /* child exception for leafs, leaflists, anyxml and groupings */
792 if (elem->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA | LYS_GROUPING)) {
793 next = NULL;
794 }
795 if (!next) {
796 /* no children, try siblings */
797 next = elem->next;
798 }
799 while (!next) {
800 /* parent is already processed, go to its sibling */
801 elem = lys_parent(elem);
802 if (!elem) {
803 /* we are done, no next element to process */
804 break;
805 }
806 /* no siblings, go back through parents */
807 next = elem->next;
808 }
809 }
810 }
Michal Vasko4be5fa22017-02-07 10:12:32 +0100811}
Radek Krejci85a54be2016-10-20 12:39:56 +0200812
Michal Vasko4be5fa22017-02-07 10:12:32 +0100813static int
Radek Krejci83a4bac2017-02-07 15:53:04 +0100814ctx_modules_redo_backlinks(struct ly_set *mods)
Michal Vasko4be5fa22017-02-07 10:12:32 +0100815{
Radek Krejci83a4bac2017-02-07 15:53:04 +0100816 unsigned int i, j, k, s;
817 struct lys_module *mod;
818 struct lys_node *next, *elem;
819 struct lys_type *type;
820 struct lys_feature *feat;
Michal Vasko4be5fa22017-02-07 10:12:32 +0100821
Michal Vasko4be5fa22017-02-07 10:12:32 +0100822 for (i = 0; i < mods->number; ++i) {
Radek Krejci83a4bac2017-02-07 15:53:04 +0100823 mod = (struct lys_module *)mods->set.g[i]; /* shortcut */
Michal Vasko4be5fa22017-02-07 10:12:32 +0100824
Radek Krejci83a4bac2017-02-07 15:53:04 +0100825 /* identities */
Radek Krejci9e6af732017-04-27 14:40:25 +0200826 if (mod->implemented) {
827 for (j = 0; j < mod->ident_size; j++) {
828 for (k = 0; k < mod->ident[j].base_size; k++) {
829 resolve_identity_backlink_update(&mod->ident[j], mod->ident[j].base[k]);
830 }
Radek Krejci83a4bac2017-02-07 15:53:04 +0100831 }
832 }
Michal Vasko4be5fa22017-02-07 10:12:32 +0100833
Radek Krejci83a4bac2017-02-07 15:53:04 +0100834 /* features */
835 for (j = 0; j < mod->features_size; j++) {
836 for (k = 0; k < mod->features[j].iffeature_size; k++) {
837 resolve_iffeature_getsizes(&mod->features[j].iffeature[k], NULL, &s);
838 while (s--) {
839 feat = mod->features[j].iffeature[k].features[s]; /* shortcut */
840 if (!feat->depfeatures) {
841 feat->depfeatures = ly_set_new();
842 }
843 ly_set_add(feat->depfeatures, &mod->features[j], LY_SET_OPT_USEASLIST);
844 }
845 }
846 }
847
848 /* leafrefs */
849 LY_TREE_DFS_BEGIN(mod->data, next, elem) {
Michal Vaskofa3d2f72017-04-10 13:30:44 +0200850 if (elem->nodetype == LYS_GROUPING) {
851 goto next_sibling;
852 }
853
Radek Krejci83a4bac2017-02-07 15:53:04 +0100854 if (elem->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
855 type = &((struct lys_node_leaf *)elem)->type; /* shortcut */
856 if (type->base == LY_TYPE_LEAFREF) {
857 lys_leaf_add_leafref_target(type->info.lref.target, elem);
858 }
859 }
860
Michal Vaskofa3d2f72017-04-10 13:30:44 +0200861 /* select element for the next run - children first */
862 next = elem->child;
863
864 /* child exception for leafs, leaflists and anyxml without children */
865 if (elem->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
866 next = NULL;
867 }
868 if (!next) {
869next_sibling:
870 /* no children */
871 if (elem == mod->data) {
872 /* we are done, (START) has no children */
873 break;
874 }
875 /* try siblings */
876 next = elem->next;
877 }
878 while (!next) {
879 /* parent is already processed, go to its sibling */
880 elem = lys_parent(elem);
881
882 /* no siblings, go back through parents */
883 if (lys_parent(elem) == lys_parent(mod->data)) {
884 /* we are done, no next element to process */
885 break;
886 }
887 next = elem->next;
888 }
Radek Krejci83a4bac2017-02-07 15:53:04 +0100889 }
Michal Vasko4be5fa22017-02-07 10:12:32 +0100890 }
891
892 return 0;
Radek Krejci85a54be2016-10-20 12:39:56 +0200893}
894
Radek Krejci8c107fe2016-10-17 16:00:18 +0200895API int
Radek Krejci0ec51da2016-12-14 16:42:03 +0100896lys_set_disabled(const struct lys_module *module)
897{
898 struct ly_ctx *ctx; /* shortcut */
899 struct lys_module *mod;
900 struct ly_set *mods;
901 uint8_t j, imported;
902 int i, o;
Radek Krejci29eac3d2017-06-01 16:50:02 +0200903 unsigned int u, v;
Radek Krejci0ec51da2016-12-14 16:42:03 +0100904
905 if (!module) {
906 ly_errno = LY_EINVAL;
907 return EXIT_FAILURE;
908 } else if (module->disabled) {
909 /* already disabled module */
910 return EXIT_SUCCESS;
911 }
912 mod = (struct lys_module *)module;
913 ctx = mod->ctx;
914
915 /* avoid disabling internal modules */
Michal Vasko2d051a12017-04-21 09:28:57 +0200916 for (i = 0; i < LY_INTERNAL_MODULE_COUNT; i++) {
Radek Krejci0ec51da2016-12-14 16:42:03 +0100917 if (mod == ctx->models.list[i]) {
Michal Vasko2d051a12017-04-21 09:28:57 +0200918 LOGERR(LY_EINVAL, "Internal module \"%s\" cannot be disabled.", mod->name);
Radek Krejci0ec51da2016-12-14 16:42:03 +0100919 return EXIT_FAILURE;
920 }
921 }
922
923 /* disable the module */
924 mod->disabled = 1;
925
926 /* get the complete list of modules to disable because of dependencies,
927 * we are going also to disable all the imported (not implemented) modules
928 * that are not used in any other module */
929 mods = ly_set_new();
930 ly_set_add(mods, mod, 0);
931checkdependency:
Michal Vasko2d051a12017-04-21 09:28:57 +0200932 for (i = LY_INTERNAL_MODULE_COUNT; i < ctx->models.used; i++) {
Radek Krejci0ec51da2016-12-14 16:42:03 +0100933 mod = ctx->models.list[i]; /* shortcut */
934 if (mod->disabled) {
935 /* skip the already disabled modules */
936 continue;
937 }
938
939 /* check depndency of imported modules */
940 for (j = 0; j < mod->imp_size; j++) {
941 for (u = 0; u < mods->number; u++) {
942 if (mod->imp[j].module == mods->set.g[u]) {
943 /* module is importing some module to disable, so it must be also disabled */
944 mod->disabled = 1;
945 ly_set_add(mods, mod, 0);
946 /* we have to start again because some of the already checked modules can
947 * depend on the one we have just decided to disable */
948 goto checkdependency;
949 }
950 }
951 }
952 /* check if the imported module is used in any module supposed to be kept */
953 if (!mod->implemented) {
954 imported = 0;
Michal Vasko2d051a12017-04-21 09:28:57 +0200955 for (o = LY_INTERNAL_MODULE_COUNT; o < ctx->models.used; o++) {
Radek Krejci0ec51da2016-12-14 16:42:03 +0100956 if (ctx->models.list[o]->disabled) {
957 /* skip modules already disabled */
958 continue;
959 }
960 for (j = 0; j < ctx->models.list[o]->imp_size; j++) {
961 if (ctx->models.list[o]->imp[j].module == mod) {
962 /* the module is used in some other module not yet selected to be disabled */
963 imported = 1;
964 goto imported;
965 }
966 }
967 }
968imported:
969 if (!imported) {
970 /* module is not implemented and neither imported by any other module in context
971 * which is supposed to be kept enabled after this operation, so we are going to disable also
972 * this module */
973 mod->disabled = 1;
974 ly_set_add(mods, mod, 0);
975 /* we have to start again, this time not because other module can depend on this one
976 * (we know that there is no such module), but because the module can import module
977 * that could became useless. If there are no imports, we can continue */
978 if (mod->imp_size) {
979 goto checkdependency;
980 }
981 }
982 }
983 }
984
985 /* before removing applied deviations, augments and updating leafrefs, we have to enable the modules
986 * to disable to allow all that operations */
987 for (u = 0; u < mods->number; u++) {
988 ((struct lys_module *)mods->set.g[u])->disabled = 0;
989 }
990
991 /* maintain backlinks (start with internal ietf-yang-library which have leafs as possible targets of leafrefs */
Michal Vasko4be5fa22017-02-07 10:12:32 +0100992 ctx_modules_undo_backlinks(ctx, mods);
Radek Krejci0ec51da2016-12-14 16:42:03 +0100993
994 /* remove the applied deviations and augments */
995 for (u = 0; u < mods->number; u++) {
996 lys_sub_module_remove_devs_augs((struct lys_module *)mods->set.g[u]);
997 }
998
Radek Krejci29eac3d2017-06-01 16:50:02 +0200999 /* now again disable the modules to disable and disable also all its submodules */
Radek Krejci0ec51da2016-12-14 16:42:03 +01001000 for (u = 0; u < mods->number; u++) {
Radek Krejci29eac3d2017-06-01 16:50:02 +02001001 mod = (struct lys_module *)mods->set.g[u];
1002 mod->disabled = 1;
1003 for (v = 0; v < mod->inc_size; v++) {
1004 mod->inc[v].submodule->disabled = 1;
1005 }
Radek Krejci0ec51da2016-12-14 16:42:03 +01001006 }
1007
1008 /* free the set */
1009 ly_set_free(mods);
1010
1011 /* update the module-set-id */
1012 ctx->models.module_set_id++;
1013
1014 return EXIT_SUCCESS;
1015}
1016
1017static void
1018lys_set_enabled_(struct ly_set *mods, struct lys_module *mod)
1019{
1020 unsigned int i;
1021
1022 ly_set_add(mods, mod, 0);
1023 mod->disabled = 0;
1024
Radek Krejci29eac3d2017-06-01 16:50:02 +02001025 for (i = 0; i < mod->inc_size; i++) {
1026 mod->inc[i].submodule->disabled = 0;
1027 }
1028
Radek Krejci0ec51da2016-12-14 16:42:03 +01001029 /* go recursively */
1030 for (i = 0; i < mod->imp_size; i++) {
1031 if (!mod->imp[i].module->disabled) {
1032 continue;
1033 }
1034
1035 lys_set_enabled_(mods, mod->imp[i].module);
1036 }
1037}
1038
1039API int
1040lys_set_enabled(const struct lys_module *module)
1041{
1042 struct ly_ctx *ctx; /* shortcut */
1043 struct lys_module *mod;
1044 struct ly_set *mods, *disabled;
1045 int i;
Radek Krejci29eac3d2017-06-01 16:50:02 +02001046 unsigned int u, v, w;
Radek Krejci0ec51da2016-12-14 16:42:03 +01001047
1048 if (!module) {
1049 ly_errno = LY_EINVAL;
1050 return EXIT_FAILURE;
1051 } else if (!module->disabled) {
1052 /* already enabled module */
1053 return EXIT_SUCCESS;
1054 }
1055 mod = (struct lys_module *)module;
1056 ctx = mod->ctx;
1057
1058 /* avoid disabling internal modules */
Michal Vasko2d051a12017-04-21 09:28:57 +02001059 for (i = 0; i < LY_INTERNAL_MODULE_COUNT; i++) {
Radek Krejci0ec51da2016-12-14 16:42:03 +01001060 if (mod == ctx->models.list[i]) {
1061 LOGERR(LY_EINVAL, "Internal module \"%s\" cannot be removed.", mod->name);
1062 return EXIT_FAILURE;
1063 }
1064 }
1065
1066 mods = ly_set_new();
1067 disabled = ly_set_new();
1068
1069 /* enable the module, including its dependencies */
1070 lys_set_enabled_(mods, mod);
1071
1072 /* we will go through the all disabled modules in the context, if the module has no dependency (import)
1073 * that is still disabled AND at least one of its imported module is from the set we are enabling now,
1074 * it is going to be also enabled. This way we try to revert everething that was possibly done by
1075 * lys_set_disabled(). */
1076checkdependency:
Michal Vasko2d051a12017-04-21 09:28:57 +02001077 for (i = LY_INTERNAL_MODULE_COUNT; i < ctx->models.used; i++) {
Radek Krejci0ec51da2016-12-14 16:42:03 +01001078 mod = ctx->models.list[i]; /* shortcut */
1079 if (!mod->disabled || ly_set_contains(disabled, mod) != -1) {
1080 /* skip the enabled modules */
1081 continue;
1082 }
1083
1084 /* check imported modules */
1085 for (u = 0; u < mod->imp_size; u++) {
1086 if (mod->imp[u].module->disabled) {
1087 /* it has disabled dependency so it must stay disabled */
1088 break;
1089 }
1090 }
1091 if (u < mod->imp_size) {
1092 /* it has disabled dependency, continue with the next module in the context */
1093 continue;
1094 }
1095
1096 /* get know if at least one of the imported modules is being enabled this time */
1097 for (u = 0; u < mod->imp_size; u++) {
1098 for (v = 0; v < mods->number; v++) {
1099 if (mod->imp[u].module == mods->set.g[v]) {
1100 /* yes, it is, so they are connected and we are going to enable it as well,
1101 * it is not necessary to call recursive lys_set_enable_() because we already
1102 * know that there is no disabled import to enable */
1103 mod->disabled = 0;
1104 ly_set_add(mods, mod, 0);
Radek Krejci29eac3d2017-06-01 16:50:02 +02001105 for (w = 0; w < mod->inc_size; w++) {
1106 mod->inc[w].submodule->disabled = 0;
1107 }
Radek Krejci0ec51da2016-12-14 16:42:03 +01001108 /* we have to start again because some of the already checked modules can
1109 * depend on the one we have just decided to enable */
1110 goto checkdependency;
1111 }
1112 }
1113 }
1114
1115 /* this module is disabled, but it does not depend on any other disabled module and none
1116 * of its imports was not enabled in this call. No future enabling of the disabled module
1117 * will change this so we can remember the module and skip it next time we will have to go
1118 * through the all context because of the checkdependency goto.
1119 */
1120 ly_set_add(disabled, mod, 0);
1121 }
1122
1123 /* maintain backlinks (start with internal ietf-yang-library which have leafs as possible targets of leafrefs */
Radek Krejci83a4bac2017-02-07 15:53:04 +01001124 ctx_modules_redo_backlinks(mods);
Radek Krejci0ec51da2016-12-14 16:42:03 +01001125
1126 /* re-apply the deviations and augments */
1127 for (v = 0; v < mods->number; v++) {
1128 lys_sub_module_apply_devs_augs((struct lys_module *)mods->set.g[v]);
1129 }
1130
1131 /* free the sets */
1132 ly_set_free(mods);
1133 ly_set_free(disabled);
1134
1135 /* update the module-set-id */
1136 ctx->models.module_set_id++;
1137
1138 return EXIT_SUCCESS;
1139}
1140
1141API int
1142ly_ctx_remove_module(const struct lys_module *module,
Radek Krejci8c107fe2016-10-17 16:00:18 +02001143 void (*private_destructor)(const struct lys_node *node, void *priv))
1144{
Radek Krejci0ec51da2016-12-14 16:42:03 +01001145 struct ly_ctx *ctx; /* shortcut */
Radek Krejci8c107fe2016-10-17 16:00:18 +02001146 struct lys_module *mod = NULL;
1147 struct ly_set *mods;
1148 uint8_t j, imported;
1149 int i, o;
1150 unsigned int u;
1151
Radek Krejci0ec51da2016-12-14 16:42:03 +01001152 if (!module) {
Radek Krejci8c107fe2016-10-17 16:00:18 +02001153 ly_errno = LY_EINVAL;
1154 return EXIT_FAILURE;
1155 }
1156
Radek Krejci0ec51da2016-12-14 16:42:03 +01001157 mod = (struct lys_module *)module;
1158 ctx = mod->ctx;
1159
Radek Krejci8c107fe2016-10-17 16:00:18 +02001160 /* avoid removing internal modules ... */
Michal Vasko2d051a12017-04-21 09:28:57 +02001161 for (i = 0; i < LY_INTERNAL_MODULE_COUNT; i++) {
Radek Krejci8c107fe2016-10-17 16:00:18 +02001162 if (mod == ctx->models.list[i]) {
Radek Krejci0ec51da2016-12-14 16:42:03 +01001163 LOGERR(LY_EINVAL, "Internal module \"%s\" cannot be removed.", mod->name);
Radek Krejci8c107fe2016-10-17 16:00:18 +02001164 return EXIT_FAILURE;
1165 }
1166 }
1167 /* ... and hide the module from the further processing of the context modules list */
Michal Vasko2d051a12017-04-21 09:28:57 +02001168 for (i = LY_INTERNAL_MODULE_COUNT; i < ctx->models.used; i++) {
Radek Krejci8c107fe2016-10-17 16:00:18 +02001169 if (mod == ctx->models.list[i]) {
1170 ctx->models.list[i] = NULL;
1171 break;
1172 }
1173 }
1174
1175 /* get the complete list of modules to remove because of dependencies,
1176 * we are going also to remove all the imported (not implemented) modules
1177 * that are not used in any other module */
1178 mods = ly_set_new();
1179 ly_set_add(mods, mod, 0);
1180checkdependency:
Michal Vasko2d051a12017-04-21 09:28:57 +02001181 for (i = LY_INTERNAL_MODULE_COUNT; i < ctx->models.used; i++) {
Radek Krejci8c107fe2016-10-17 16:00:18 +02001182 mod = ctx->models.list[i]; /* shortcut */
1183 if (!mod) {
1184 /* skip modules already selected for removing */
1185 continue;
1186 }
1187
1188 /* check depndency of imported modules */
1189 for (j = 0; j < mod->imp_size; j++) {
1190 for (u = 0; u < mods->number; u++) {
1191 if (mod->imp[j].module == mods->set.g[u]) {
1192 /* module is importing some module to remove, so it must be also removed */
1193 ly_set_add(mods, mod, 0);
1194 ctx->models.list[i] = NULL;
1195 /* we have to start again because some of the already checked modules can
1196 * depend on the one we have just decided to remove */
1197 goto checkdependency;
1198 }
1199 }
1200 }
1201 /* check if the imported module is used in any module supposed to be kept */
1202 if (!mod->implemented) {
1203 imported = 0;
Michal Vasko2d051a12017-04-21 09:28:57 +02001204 for (o = LY_INTERNAL_MODULE_COUNT; o < ctx->models.used; o++) {
Radek Krejci8c107fe2016-10-17 16:00:18 +02001205 if (!ctx->models.list[o]) {
1206 /* skip modules already selected for removing */
1207 continue;
1208 }
1209 for (j = 0; j < ctx->models.list[o]->imp_size; j++) {
1210 if (ctx->models.list[o]->imp[j].module == mod) {
1211 /* the module is used in some other module not yet selected to be deleted */
1212 imported = 1;
1213 goto imported;
1214 }
1215 }
1216 }
1217imported:
1218 if (!imported) {
1219 /* module is not implemented and neither imported by any other module in context
1220 * which is supposed to be kept after this operation, so we are going to remove also
1221 * this useless module */
1222 ly_set_add(mods, mod, 0);
1223 ctx->models.list[i] = NULL;
1224 /* we have to start again, this time not because other module can depend on this one
Radek Krejci0ec51da2016-12-14 16:42:03 +01001225 * (we know that there is no such module), but because the module can import module
Radek Krejci8c107fe2016-10-17 16:00:18 +02001226 * that could became useless. If there are no imports, we can continue */
1227 if (mod->imp_size) {
1228 goto checkdependency;
1229 }
1230 }
1231 }
1232 }
1233
Radek Krejci8c107fe2016-10-17 16:00:18 +02001234
1235 /* consolidate the modules list */
Michal Vasko2d051a12017-04-21 09:28:57 +02001236 for (i = o = LY_INTERNAL_MODULE_COUNT; i < ctx->models.used; i++) {
Radek Krejci8c107fe2016-10-17 16:00:18 +02001237 if (ctx->models.list[o]) {
1238 /* used cell */
1239 o++;
1240 } else {
1241 /* the current output cell is empty, move here an input cell */
1242 ctx->models.list[o] = ctx->models.list[i];
1243 ctx->models.list[i] = NULL;
1244 }
1245 }
1246 /* get the last used cell to get know the number of used */
1247 while (!ctx->models.list[o]) {
1248 o--;
1249 }
1250 ctx->models.used = o + 1;
1251 ctx->models.module_set_id++;
1252
Radek Krejci85a54be2016-10-20 12:39:56 +02001253 /* maintain backlinks (start with internal ietf-yang-library which have leafs as possible targets of leafrefs */
Michal Vasko4be5fa22017-02-07 10:12:32 +01001254 ctx_modules_undo_backlinks(ctx, mods);
Radek Krejci85a54be2016-10-20 12:39:56 +02001255
1256 /* free the modules */
1257 for (u = 0; u < mods->number; u++) {
Radek Krejcib2541a32016-12-12 16:45:57 +01001258 /* remove the applied deviations and augments */
1259 lys_sub_module_remove_devs_augs((struct lys_module *)mods->set.g[u]);
Radek Krejci85a54be2016-10-20 12:39:56 +02001260 /* remove the module */
1261 lys_free((struct lys_module *)mods->set.g[u], private_destructor, 0);
1262 }
1263 ly_set_free(mods);
1264
Radek Krejci8c107fe2016-10-17 16:00:18 +02001265 return EXIT_SUCCESS;
1266}
1267
Radek Krejci85a54be2016-10-20 12:39:56 +02001268API void
1269ly_ctx_clean(struct ly_ctx *ctx, void (*private_destructor)(const struct lys_node *node, void *priv))
1270{
Radek Krejci85a54be2016-10-20 12:39:56 +02001271 if (!ctx) {
1272 return;
1273 }
1274
1275 /* models list */
Michal Vasko2d051a12017-04-21 09:28:57 +02001276 for (; ctx->models.used > LY_INTERNAL_MODULE_COUNT; ctx->models.used--) {
Radek Krejcifc8411a2017-02-03 10:26:05 +01001277 /* remove the applied deviations and augments */
Radek Krejcic436a232017-02-08 14:43:11 +01001278 lys_sub_module_remove_devs_augs(ctx->models.list[ctx->models.used - 1]);
Radek Krejcifc8411a2017-02-03 10:26:05 +01001279 /* remove the module */
Radek Krejcic436a232017-02-08 14:43:11 +01001280 lys_free(ctx->models.list[ctx->models.used - 1], private_destructor, 0);
Radek Krejcifc8411a2017-02-03 10:26:05 +01001281 /* clean it for safer future use */
Radek Krejcic436a232017-02-08 14:43:11 +01001282 ctx->models.list[ctx->models.used - 1] = NULL;
Radek Krejci85a54be2016-10-20 12:39:56 +02001283 }
Radek Krejci85a54be2016-10-20 12:39:56 +02001284 ctx->models.module_set_id++;
1285
Radek Krejci83a4bac2017-02-07 15:53:04 +01001286 /* maintain backlinks (actually done only with ietf-yang-library since its leafs can be target of leafref) */
Michal Vasko4be5fa22017-02-07 10:12:32 +01001287 ctx_modules_undo_backlinks(ctx, NULL);
Radek Krejci85a54be2016-10-20 12:39:56 +02001288}
1289
Michal Vaskod7957c02016-04-01 10:27:26 +02001290API const struct lys_module *
1291ly_ctx_get_module_iter(const struct ly_ctx *ctx, uint32_t *idx)
1292{
1293 if (!ctx || !idx) {
1294 ly_errno = LY_EINVAL;
1295 return NULL;
1296 }
1297
Radek Krejci0ec51da2016-12-14 16:42:03 +01001298 for ( ; *idx < (unsigned)ctx->models.used; (*idx)++) {
1299 if (!ctx->models.list[(*idx)]->disabled) {
1300 return ctx->models.list[(*idx)++];
1301 }
1302 }
1303
1304 return NULL;
1305}
1306
1307API const struct lys_module *
1308ly_ctx_get_disabled_module_iter(const struct ly_ctx *ctx, uint32_t *idx)
1309{
1310 if (!ctx || !idx) {
1311 ly_errno = LY_EINVAL;
Michal Vaskod7957c02016-04-01 10:27:26 +02001312 return NULL;
1313 }
1314
Radek Krejci0ec51da2016-12-14 16:42:03 +01001315 for ( ; *idx < (unsigned)ctx->models.used; (*idx)++) {
1316 if (ctx->models.list[(*idx)]->disabled) {
1317 return ctx->models.list[(*idx)++];
1318 }
1319 }
1320
1321 return NULL;
Michal Vaskod7957c02016-04-01 10:27:26 +02001322}
1323
Michal Vasko209a6222015-10-16 09:51:07 +02001324static int
1325ylib_feature(struct lyd_node *parent, struct lys_module *cur_mod)
1326{
1327 int i, j;
1328
1329 /* module features */
1330 for (i = 0; i < cur_mod->features_size; ++i) {
1331 if (!(cur_mod->features[i].flags & LYS_FENABLED)) {
1332 continue;
1333 }
1334
Michal Vasko3e671b52015-10-23 16:23:15 +02001335 if (!lyd_new_leaf(parent, NULL, "feature", cur_mod->features[i].name)) {
Michal Vasko209a6222015-10-16 09:51:07 +02001336 return EXIT_FAILURE;
1337 }
1338 }
1339
1340 /* submodule features */
Radek Krejcic071c542016-01-27 14:57:51 +01001341 for (i = 0; i < cur_mod->inc_size && cur_mod->inc[i].submodule; ++i) {
Michal Vasko209a6222015-10-16 09:51:07 +02001342 for (j = 0; j < cur_mod->inc[i].submodule->features_size; ++j) {
1343 if (!(cur_mod->inc[i].submodule->features[j].flags & LYS_FENABLED)) {
1344 continue;
1345 }
1346
Michal Vasko3e671b52015-10-23 16:23:15 +02001347 if (!lyd_new_leaf(parent, NULL, "feature", cur_mod->inc[i].submodule->features[j].name)) {
Michal Vasko209a6222015-10-16 09:51:07 +02001348 return EXIT_FAILURE;
1349 }
1350 }
1351 }
1352
1353 return EXIT_SUCCESS;
1354}
1355
1356static int
Michal Vaskoff006c12016-02-17 11:15:19 +01001357ylib_deviation(struct lyd_node *parent, struct lys_module *cur_mod)
Michal Vasko97d8c6d2016-02-12 11:05:48 +01001358{
Michal Vasko89563fc2016-07-28 16:19:35 +02001359 uint32_t i = 0, j;
1360 const struct lys_module *mod;
Michal Vasko209a6222015-10-16 09:51:07 +02001361 struct lyd_node *cont;
Michal Vasko89563fc2016-07-28 16:19:35 +02001362 const char *ptr;
Michal Vasko209a6222015-10-16 09:51:07 +02001363
Michal Vasko89563fc2016-07-28 16:19:35 +02001364 if (cur_mod->deviated) {
1365 while ((mod = ly_ctx_get_module_iter(cur_mod->ctx, &i))) {
1366 if (mod == cur_mod) {
1367 continue;
Michal Vasko209a6222015-10-16 09:51:07 +02001368 }
Michal Vasko209a6222015-10-16 09:51:07 +02001369
Michal Vasko89563fc2016-07-28 16:19:35 +02001370 for (j = 0; j < mod->deviation_size; ++j) {
1371 ptr = strstr(mod->deviation[j].target_name, cur_mod->name);
1372 if (ptr && ptr[strlen(cur_mod->name)] == ':') {
1373 cont = lyd_new(parent, NULL, "deviation");
1374 if (!cont) {
1375 return EXIT_FAILURE;
1376 }
1377
1378 if (!lyd_new_leaf(cont, NULL, "name", mod->name)) {
1379 return EXIT_FAILURE;
1380 }
1381 if (!lyd_new_leaf(cont, NULL, "revision", (mod->rev_size ? mod->rev[0].date : ""))) {
1382 return EXIT_FAILURE;
1383 }
Michal Vasko0c2215b2016-08-25 14:18:43 +02001384
1385 break;
Michal Vasko89563fc2016-07-28 16:19:35 +02001386 }
Michal Vasko209a6222015-10-16 09:51:07 +02001387 }
1388 }
1389 }
1390
1391 return EXIT_SUCCESS;
1392}
1393
1394static int
1395ylib_submodules(struct lyd_node *parent, struct lys_module *cur_mod)
1396{
1397 int i;
Radek Krejcia77904e2016-02-25 16:23:45 +01001398 char *str;
Radek Krejcid9723912016-09-16 17:06:06 +02001399 struct lyd_node *item;
Michal Vasko209a6222015-10-16 09:51:07 +02001400
Radek Krejcic071c542016-01-27 14:57:51 +01001401 for (i = 0; i < cur_mod->inc_size && cur_mod->inc[i].submodule; ++i) {
Radek Krejcid9723912016-09-16 17:06:06 +02001402 item = lyd_new(parent, NULL, "submodule");
Radek Krejci6e05cea2015-12-10 16:34:37 +01001403 if (!item) {
Michal Vasko209a6222015-10-16 09:51:07 +02001404 return EXIT_FAILURE;
1405 }
1406
Radek Krejci6e05cea2015-12-10 16:34:37 +01001407 if (!lyd_new_leaf(item, NULL, "name", cur_mod->inc[i].submodule->name)) {
Michal Vasko209a6222015-10-16 09:51:07 +02001408 return EXIT_FAILURE;
1409 }
Radek Krejci6e05cea2015-12-10 16:34:37 +01001410 if (!lyd_new_leaf(item, NULL, "revision", (cur_mod->inc[i].submodule->rev_size ?
Michal Vasko3e671b52015-10-23 16:23:15 +02001411 cur_mod->inc[i].submodule->rev[0].date : ""))) {
Michal Vasko209a6222015-10-16 09:51:07 +02001412 return EXIT_FAILURE;
1413 }
Radek Krejcia77904e2016-02-25 16:23:45 +01001414 if (cur_mod->inc[i].submodule->filepath) {
Radek Krejci95aa2012016-03-03 11:21:09 +01001415 if (asprintf(&str, "file://%s", cur_mod->inc[i].submodule->filepath) == -1) {
Radek Krejcia77904e2016-02-25 16:23:45 +01001416 LOGMEM;
1417 return EXIT_FAILURE;
Radek Krejci6e65af92016-03-07 12:48:19 +01001418 } else if (!lyd_new_leaf(item, NULL, "schema", str)) {
Radek Krejci19f9ede2016-02-25 16:29:21 +01001419 free(str);
Radek Krejcia77904e2016-02-25 16:23:45 +01001420 return EXIT_FAILURE;
1421 }
Radek Krejci19f9ede2016-02-25 16:29:21 +01001422 free(str);
Michal Vasko209a6222015-10-16 09:51:07 +02001423 }
1424 }
1425
1426 return EXIT_SUCCESS;
1427}
1428
1429API struct lyd_node *
1430ly_ctx_info(struct ly_ctx *ctx)
1431{
1432 int i;
1433 char id[8];
Radek Krejcia77904e2016-02-25 16:23:45 +01001434 char *str;
Michal Vasko1e62a092015-12-01 12:27:20 +01001435 const struct lys_module *mod;
Michal Vasko209a6222015-10-16 09:51:07 +02001436 struct lyd_node *root, *cont;
1437
Michal Vasko7eccc6c2016-03-24 14:56:33 +01001438 if (!ctx) {
1439 ly_errno = LY_EINVAL;
1440 return NULL;
1441 }
1442
Radek Krejcibd9e8d22016-02-03 14:11:48 +01001443 mod = ly_ctx_get_module(ctx, "ietf-yang-library", IETF_YANG_LIB_REV);
1444 if (!mod || !mod->data) {
1445 LOGINT;
Michal Vasko209a6222015-10-16 09:51:07 +02001446 return NULL;
1447 }
1448
Radek Krejcibd9e8d22016-02-03 14:11:48 +01001449 root = lyd_new(NULL, mod, "modules-state");
Michal Vasko209a6222015-10-16 09:51:07 +02001450 if (!root) {
1451 return NULL;
1452 }
1453
1454 for (i = 0; i < ctx->models.used; ++i) {
Radek Krejci0ec51da2016-12-14 16:42:03 +01001455 if (ctx->models.list[i]->disabled) {
1456 /* skip the disabled modules */
1457 continue;
1458 }
1459
Michal Vasko209a6222015-10-16 09:51:07 +02001460 cont = lyd_new(root, NULL, "module");
1461 if (!cont) {
1462 lyd_free(root);
1463 return NULL;
1464 }
1465
Michal Vasko3e671b52015-10-23 16:23:15 +02001466 if (!lyd_new_leaf(cont, NULL, "name", ctx->models.list[i]->name)) {
Michal Vasko209a6222015-10-16 09:51:07 +02001467 lyd_free(root);
1468 return NULL;
1469 }
Michal Vasko3e671b52015-10-23 16:23:15 +02001470 if (!lyd_new_leaf(cont, NULL, "revision", (ctx->models.list[i]->rev_size ?
Michal Vasko209a6222015-10-16 09:51:07 +02001471 ctx->models.list[i]->rev[0].date : ""))) {
1472 lyd_free(root);
1473 return NULL;
1474 }
Radek Krejcia77904e2016-02-25 16:23:45 +01001475 if (ctx->models.list[i]->filepath) {
Radek Krejci15412ca2016-03-03 11:16:52 +01001476 if (asprintf(&str, "file://%s", ctx->models.list[i]->filepath) == -1) {
Radek Krejcia77904e2016-02-25 16:23:45 +01001477 LOGMEM;
1478 lyd_free(root);
1479 return NULL;
1480 } else if (!lyd_new_leaf(cont, NULL, "schema", str)) {
Radek Krejci19f9ede2016-02-25 16:29:21 +01001481 free(str);
Radek Krejcia77904e2016-02-25 16:23:45 +01001482 lyd_free(root);
1483 return NULL;
1484 }
Radek Krejci19f9ede2016-02-25 16:29:21 +01001485 free(str);
Michal Vasko209a6222015-10-16 09:51:07 +02001486 }
Michal Vasko3e671b52015-10-23 16:23:15 +02001487 if (!lyd_new_leaf(cont, NULL, "namespace", ctx->models.list[i]->ns)) {
Michal Vasko209a6222015-10-16 09:51:07 +02001488 lyd_free(root);
1489 return NULL;
1490 }
1491 if (ylib_feature(cont, ctx->models.list[i])) {
1492 lyd_free(root);
1493 return NULL;
1494 }
Michal Vaskoff006c12016-02-17 11:15:19 +01001495 if (ylib_deviation(cont, ctx->models.list[i])) {
Michal Vasko209a6222015-10-16 09:51:07 +02001496 lyd_free(root);
1497 return NULL;
1498 }
1499 if (ctx->models.list[i]->implemented
Radek Krejcibd9e8d22016-02-03 14:11:48 +01001500 && !lyd_new_leaf(cont, NULL, "conformance-type", "implement")) {
Michal Vasko209a6222015-10-16 09:51:07 +02001501 lyd_free(root);
1502 return NULL;
1503 }
1504 if (!ctx->models.list[i]->implemented
Radek Krejcibd9e8d22016-02-03 14:11:48 +01001505 && !lyd_new_leaf(cont, NULL, "conformance-type", "import")) {
Michal Vasko209a6222015-10-16 09:51:07 +02001506 lyd_free(root);
1507 return NULL;
1508 }
1509 if (ylib_submodules(cont, ctx->models.list[i])) {
1510 lyd_free(root);
1511 return NULL;
1512 }
1513 }
1514
1515 sprintf(id, "%u", ctx->models.module_set_id);
Michal Vasko3e671b52015-10-23 16:23:15 +02001516 if (!lyd_new_leaf(root, mod, "module-set-id", id)) {
Michal Vasko209a6222015-10-16 09:51:07 +02001517 lyd_free(root);
1518 return NULL;
1519 }
1520
Michal Vaskocdb90172016-09-13 09:34:36 +02001521 if (lyd_validate(&root, LYD_OPT_NOSIBLINGS, NULL)) {
Michal Vasko209a6222015-10-16 09:51:07 +02001522 lyd_free(root);
1523 return NULL;
1524 }
1525
1526 return root;
1527}
Michal Vaskob3744402017-08-03 14:23:58 +02001528
1529API const struct lys_node *
1530ly_ctx_get_node(struct ly_ctx *ctx, const struct lys_node *start, const char *nodeid, int output)
1531{
1532 const struct lys_node *node;
1533
1534 if (!ctx || !nodeid || ((nodeid[0] != '/') && !start)) {
1535 ly_errno = LY_EINVAL;
1536 return NULL;
1537 }
1538
1539 /* sets error and everything */
1540 node = resolve_json_nodeid(nodeid, ctx, start, output);
1541
1542 return node;
1543}