blob: d4e936b662adfef877fe4a04a2ae55384e5cd555 [file] [log] [blame]
Radek Krejcida04f4a2015-05-21 12:54:09 +02001/**
2 * @file context.c
3 * @author Radek Krejci <rkrejci@cesnet.cz>
4 * @brief context implementation for libyang
5 *
6 * Copyright (c) 2015 CESNET, z.s.p.o.
7 *
Radek Krejci54f6fb32016-02-24 12:56:39 +01008 * This source code is licensed under BSD 3-Clause License (the "License").
9 * You may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
Michal Vasko8de098c2016-02-26 10:00:25 +010011 *
Radek Krejci54f6fb32016-02-24 12:56:39 +010012 * https://opensource.org/licenses/BSD-3-Clause
Radek Krejcida04f4a2015-05-21 12:54:09 +020013 */
14
15#define _GNU_SOURCE
Radek Krejcifd4e6e32015-08-10 15:00:51 +020016#include <stddef.h>
Radek Krejcida04f4a2015-05-21 12:54:09 +020017#include <stdlib.h>
18#include <string.h>
19#include <sys/types.h>
20#include <sys/stat.h>
21#include <unistd.h>
22#include <errno.h>
23#include <fcntl.h>
24
25#include "common.h"
26#include "context.h"
Radek Krejci41912fe2015-10-22 10:22:12 +020027#include "dict_private.h"
Michal Vasko209a6222015-10-16 09:51:07 +020028#include "parser.h"
Radek Krejcibc9cf932015-07-30 11:09:39 +020029#include "tree_internal.h"
Radek Krejcida04f4a2015-05-21 12:54:09 +020030
Radek Krejcid9f7ec52016-02-11 16:27:01 +010031#define YANG_FAKEMODULE_PATH "../models/yang@2016-02-11.h"
Michal Vasko8d054e42015-08-03 12:42:06 +020032#define IETF_INET_TYPES_PATH "../models/ietf-inet-types@2013-07-15.h"
Michal Vasko21181c42015-08-03 13:46:45 +020033#define IETF_YANG_TYPES_PATH "../models/ietf-yang-types@2013-07-15.h"
Radek Krejcid9723912016-09-16 17:06:06 +020034#define IETF_YANG_LIB_PATH "../models/ietf-yang-library@2016-06-21.h"
35#define IETF_YANG_LIB_REV "2016-06-21"
Michal Vasko8d054e42015-08-03 12:42:06 +020036
Radek Krejcid9f7ec52016-02-11 16:27:01 +010037#include YANG_FAKEMODULE_PATH
Michal Vasko8d054e42015-08-03 12:42:06 +020038#include IETF_INET_TYPES_PATH
Michal Vasko21181c42015-08-03 13:46:45 +020039#include IETF_YANG_TYPES_PATH
Michal Vasko8d054e42015-08-03 12:42:06 +020040#include IETF_YANG_LIB_PATH
41
Radek Krejci03203412016-06-23 15:20:53 +020042#define INTERNAL_MODULES_COUNT 4
43static struct internal_modules_s {
44 const char *name;
45 const char *revision;
46 const char *data;
47 uint8_t implemented;
48 LYS_INFORMAT format;
49} internal_modules[INTERNAL_MODULES_COUNT] = {
50 {"yang", "2016-02-11", (const char*)yang_2016_02_11_yin, 1, LYS_IN_YIN},
51 {"ietf-inet-types", "2013-07-15", (const char*)ietf_inet_types_2013_07_15_yin, 0, LYS_IN_YIN},
52 {"ietf-yang-types", "2013-07-15", (const char*)ietf_yang_types_2013_07_15_yin, 0, LYS_IN_YIN},
Radek Krejcid9723912016-09-16 17:06:06 +020053 {"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 +020054};
55
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020056API struct ly_ctx *
57ly_ctx_new(const char *search_dir)
Radek Krejcida04f4a2015-05-21 12:54:09 +020058{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020059 struct ly_ctx *ctx;
Michal Vasko7d7de952016-05-02 17:13:14 +020060 struct lys_module *module;
Michal Vasko70b6d692015-08-03 14:05:59 +020061 char *cwd;
Radek Krejci03203412016-06-23 15:20:53 +020062 int i;
Radek Krejcida04f4a2015-05-21 12:54:09 +020063
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020064 ctx = calloc(1, sizeof *ctx);
65 if (!ctx) {
66 LOGMEM;
67 return NULL;
68 }
Radek Krejcida04f4a2015-05-21 12:54:09 +020069
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020070 /* dictionary */
71 lydict_init(&ctx->dict);
Radek Krejcida04f4a2015-05-21 12:54:09 +020072
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020073 /* models list */
74 ctx->models.list = calloc(16, sizeof *ctx->models.list);
Michal Vasko253035f2015-12-17 16:58:13 +010075 if (!ctx->models.list) {
76 LOGMEM;
77 free(ctx);
78 return NULL;
79 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020080 ctx->models.used = 0;
81 ctx->models.size = 16;
82 if (search_dir) {
83 cwd = get_current_dir_name();
84 if (chdir(search_dir)) {
85 LOGERR(LY_ESYS, "Unable to use search directory \"%s\" (%s)",
86 search_dir, strerror(errno));
87 free(cwd);
Radek Krejcifa0b5e02016-02-04 13:57:03 +010088 ly_ctx_destroy(ctx, NULL);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020089 return NULL;
90 }
91 ctx->models.search_path = get_current_dir_name();
Radek Krejci15412ca2016-03-03 11:16:52 +010092 if (chdir(cwd)) {
93 LOGWRN("Unable to return back to working directory \"%s\" (%s)",
94 cwd, strerror(errno));
95 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020096 free(cwd);
97 }
Michal Vasko14719b22015-08-03 12:47:55 +020098 ctx->models.module_set_id = 1;
99
Radek Krejci03203412016-06-23 15:20:53 +0200100 /* load internal modules */
101 for (i = 0; i < INTERNAL_MODULES_COUNT; i++) {
102 module = (struct lys_module *)lys_parse_mem(ctx, internal_modules[i].data, internal_modules[i].format);
103 if (!module) {
104 ly_ctx_destroy(ctx, NULL);
105 return NULL;
106 }
107 module->implemented = internal_modules[i].implemented;
Michal Vasko8d054e42015-08-03 12:42:06 +0200108 }
Radek Krejcida04f4a2015-05-21 12:54:09 +0200109
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200110 return ctx;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200111}
112
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200113API void
Michal Vasko60ba9a62015-07-03 14:42:31 +0200114ly_ctx_set_searchdir(struct ly_ctx *ctx, const char *search_dir)
115{
116 char *cwd;
117
118 if (!ctx) {
119 return;
120 }
121
122 if (search_dir) {
123 cwd = get_current_dir_name();
124 if (chdir(search_dir)) {
125 LOGERR(LY_ESYS, "Unable to use search directory \"%s\" (%s)",
126 search_dir, strerror(errno));
127 free(cwd);
128 return;
129 }
Michal Vasko3eff9322015-11-10 11:02:30 +0100130 free(ctx->models.search_path);
Michal Vasko60ba9a62015-07-03 14:42:31 +0200131 ctx->models.search_path = get_current_dir_name();
Michal Vasko3eff9322015-11-10 11:02:30 +0100132
Radek Krejci15412ca2016-03-03 11:16:52 +0100133 if (chdir(cwd)) {
134 LOGWRN("Unable to return back to working directory \"%s\" (%s)",
135 cwd, strerror(errno));
136 }
Michal Vasko60ba9a62015-07-03 14:42:31 +0200137 free(cwd);
138 } else {
139 free(ctx->models.search_path);
140 ctx->models.search_path = NULL;
141 }
142}
143
Radek Krejcib081d8d2015-10-21 16:29:07 +0200144API const char *
Michal Vasko1e62a092015-12-01 12:27:20 +0100145ly_ctx_get_searchdir(const struct ly_ctx *ctx)
Radek Krejci5a797572015-10-21 15:45:45 +0200146{
Radek Krejciee554172016-12-14 10:29:06 +0100147 if (!ctx) {
148 ly_errno = LY_EINVAL;
149 return NULL;
150 }
Radek Krejci5a797572015-10-21 15:45:45 +0200151 return ctx->models.search_path;
152}
153
Michal Vasko60ba9a62015-07-03 14:42:31 +0200154API void
Radek Krejcifa0b5e02016-02-04 13:57:03 +0100155ly_ctx_destroy(struct ly_ctx *ctx, void (*private_destructor)(const struct lys_node *node, void *priv))
Radek Krejcida04f4a2015-05-21 12:54:09 +0200156{
Michal Vasko627975a2016-02-11 11:39:03 +0100157 int i;
158
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200159 if (!ctx) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200160 return;
161 }
Radek Krejcida04f4a2015-05-21 12:54:09 +0200162
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200163 /* models list */
Michal Vasko627975a2016-02-11 11:39:03 +0100164 for (i = 0; i < ctx->models.used; ++i) {
165 lys_free(ctx->models.list[i], private_destructor, 0);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200166 }
167 free(ctx->models.search_path);
168 free(ctx->models.list);
Radek Krejcida04f4a2015-05-21 12:54:09 +0200169
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200170 /* dictionary */
171 lydict_clean(&ctx->dict);
Radek Krejcida04f4a2015-05-21 12:54:09 +0200172
Radek Krejci8b76a4a2016-10-26 10:02:32 +0200173 /* clean the error list */
Radek Krejci00a0e712016-10-26 10:24:46 +0200174 ly_err_clean(0);
Radek Krejci8b76a4a2016-10-26 10:02:32 +0200175
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200176 free(ctx);
Radek Krejcida04f4a2015-05-21 12:54:09 +0200177}
178
Michal Vasko1e62a092015-12-01 12:27:20 +0100179API const struct lys_submodule *
Radek Krejci62f0da72016-03-07 11:35:43 +0100180ly_ctx_get_submodule2(const struct lys_module *main_module, const char *submodule)
181{
Radek Krejcid4c1d0f2017-01-19 16:11:38 +0100182 const struct lys_submodule *result;
Radek Krejci62f0da72016-03-07 11:35:43 +0100183 int i;
184
185 if (!main_module || !submodule) {
186 ly_errno = LY_EINVAL;
187 return NULL;
188 }
189
190 /* search in submodules list */
191 for (i = 0; i < main_module->inc_size; i++) {
192 result = main_module->inc[i].submodule;
Radek Krejcid4c1d0f2017-01-19 16:11:38 +0100193 if (ly_strequal(submodule, result->name, 0)) {
Radek Krejci62f0da72016-03-07 11:35:43 +0100194 return result;
195 }
Radek Krejcid4c1d0f2017-01-19 16:11:38 +0100196
197 /* in YANG 1.1 all the submodules must be included in the main module, so we are done.
198 * YANG 1.0 allows (is unclear about denying it) to include a submodule only in another submodule
199 * but when libyang parses such a module it adds the include into the main module so we are also done.
200 */
Radek Krejci62f0da72016-03-07 11:35:43 +0100201 }
202
Radek Krejcid4c1d0f2017-01-19 16:11:38 +0100203
Radek Krejci62f0da72016-03-07 11:35:43 +0100204 return NULL;
205}
206
207API const struct lys_submodule *
Michal Vaskof6d94c62016-04-05 11:21:54 +0200208ly_ctx_get_submodule(const struct ly_ctx *ctx, const char *module, const char *revision, const char *submodule,
209 const char *sub_revision)
Radek Krejciefaeba32015-05-27 14:30:57 +0200210{
Radek Krejcie7973552016-03-07 08:12:01 +0100211 const struct lys_module *mainmod;
Michal Vaskof6d94c62016-04-05 11:21:54 +0200212 const struct lys_submodule *ret = NULL, *submod;
213 uint32_t idx = 0;
Radek Krejciefaeba32015-05-27 14:30:57 +0200214
Michal Vaskof6d94c62016-04-05 11:21:54 +0200215 if (!ctx || !submodule || (revision && !module)) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200216 ly_errno = LY_EINVAL;
217 return NULL;
218 }
Radek Krejciefaeba32015-05-27 14:30:57 +0200219
Michal Vaskof6d94c62016-04-05 11:21:54 +0200220 while ((mainmod = ly_ctx_get_module_iter(ctx, &idx))) {
221 if (module && strcmp(mainmod->name, module)) {
222 /* main module name does not match */
223 continue;
224 }
225
226 if (revision && (!mainmod->rev || strcmp(revision, mainmod->rev[0].date))) {
227 /* main module revision does not match */
228 continue;
229 }
230
231 submod = ly_ctx_get_submodule2(mainmod, submodule);
232 if (!submod) {
233 continue;
234 }
235
236 if (!sub_revision) {
237 /* store only if newer */
238 if (ret) {
239 if (submod->rev && (!ret->rev || (strcmp(submod->rev[0].date, ret->rev[0].date) > 0))) {
240 ret = submod;
241 }
242 } else {
243 ret = submod;
244 }
245 } else {
246 /* store only if revision matches, we are done if it does */
247 if (!submod->rev) {
248 continue;
249 } else if (!strcmp(sub_revision, submod->rev[0].date)) {
250 ret = submod;
251 break;
252 }
253 }
Radek Krejcia7533f22016-03-07 07:37:45 +0100254 }
Radek Krejcic071c542016-01-27 14:57:51 +0100255
Michal Vaskof6d94c62016-04-05 11:21:54 +0200256 return ret;
Radek Krejciefaeba32015-05-27 14:30:57 +0200257}
258
Michal Vasko1e62a092015-12-01 12:27:20 +0100259static const struct lys_module *
Radek Krejci0ec51da2016-12-14 16:42:03 +0100260ly_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 +0200261{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200262 int i;
Radek Krejcib8048692015-08-05 13:36:34 +0200263 struct lys_module *result = NULL;
Radek Krejciefaeba32015-05-27 14:30:57 +0200264
Radek Krejcifd4e6e32015-08-10 15:00:51 +0200265 if (!ctx || !key) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200266 ly_errno = LY_EINVAL;
267 return NULL;
268 }
Radek Krejciefaeba32015-05-27 14:30:57 +0200269
Radek Krejcidce51452015-06-16 15:20:08 +0200270 for (i = 0; i < ctx->models.used; i++) {
Radek Krejci0ec51da2016-12-14 16:42:03 +0100271 if (!with_disabled && ctx->models.list[i]->disabled) {
272 /* skip the disabled modules */
273 continue;
274 }
Radek Krejcifd4e6e32015-08-10 15:00:51 +0200275 /* use offset to get address of the pointer to string (char**), remember that offset is in
276 * bytes, so we have to cast the pointer to the module to (char*), finally, we want to have
277 * string not the pointer to string
278 */
279 if (!ctx->models.list[i] || strcmp(key, *(char**)(((char*)ctx->models.list[i]) + offset))) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200280 continue;
281 }
Radek Krejciefaeba32015-05-27 14:30:57 +0200282
Radek Krejcif647e612015-07-30 11:36:07 +0200283 if (!revision) {
284 /* compare revisons and remember the newest one */
285 if (result) {
286 if (!ctx->models.list[i]->rev_size) {
287 /* the current have no revision, keep the previous with some revision */
288 continue;
289 }
290 if (result->rev_size && strcmp(ctx->models.list[i]->rev[0].date, result->rev[0].date) < 0) {
291 /* the previous found matching module has a newer revision */
292 continue;
293 }
294 }
295
296 /* remember the current match and search for newer version */
297 result = ctx->models.list[i];
298 } else {
299 if (ctx->models.list[i]->rev_size && !strcmp(revision, ctx->models.list[i]->rev[0].date)) {
300 /* matching revision */
Michal Vasko97586502015-08-12 14:32:18 +0200301 result = ctx->models.list[i];
302 break;
Radek Krejcif647e612015-07-30 11:36:07 +0200303 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200304 }
305 }
Radek Krejciefaeba32015-05-27 14:30:57 +0200306
Radek Krejcif647e612015-07-30 11:36:07 +0200307 return result;
Radek Krejcifd4e6e32015-08-10 15:00:51 +0200308
309}
310
Michal Vasko1e62a092015-12-01 12:27:20 +0100311API const struct lys_module *
312ly_ctx_get_module_by_ns(const struct ly_ctx *ctx, const char *ns, const char *revision)
Radek Krejcifd4e6e32015-08-10 15:00:51 +0200313{
Radek Krejci0ec51da2016-12-14 16:42:03 +0100314 return ly_ctx_get_module_by(ctx, ns, offsetof(struct lys_module, ns), revision, 0);
Radek Krejcifd4e6e32015-08-10 15:00:51 +0200315}
316
Michal Vasko1e62a092015-12-01 12:27:20 +0100317API const struct lys_module *
318ly_ctx_get_module(const struct ly_ctx *ctx, const char *name, const char *revision)
Radek Krejcifd4e6e32015-08-10 15:00:51 +0200319{
Radek Krejci0ec51da2016-12-14 16:42:03 +0100320 return ly_ctx_get_module_by(ctx, name, offsetof(struct lys_module, name), revision, 0);
Radek Krejcida04f4a2015-05-21 12:54:09 +0200321}
Michal Vasko3ec07dc2015-06-30 15:51:30 +0200322
Radek Krejci21601a32016-03-07 11:39:27 +0100323API const struct lys_module *
324ly_ctx_get_module_older(const struct ly_ctx *ctx, const struct lys_module *module)
325{
326 int i;
327 const struct lys_module *result = NULL, *iter;
328
329 if (!ctx || !module || !module->rev_size) {
330 ly_errno = LY_EINVAL;
331 return NULL;
332 }
333
334
335 for (i = 0; i < ctx->models.used; i++) {
336 iter = ctx->models.list[i];
Radek Krejci0ec51da2016-12-14 16:42:03 +0100337 if (iter->disabled) {
338 /* skip the disabled modules */
339 continue;
340 }
Radek Krejci21601a32016-03-07 11:39:27 +0100341 if (iter == module || !iter->rev_size) {
342 /* iter is the module itself or iter has no revision */
343 continue;
344 }
345 if (!ly_strequal(module->name, iter->name, 0)) {
346 /* different module */
347 continue;
348 }
349 if (strcmp(iter->rev[0].date, module->rev[0].date) < 0) {
350 /* iter is older than module */
351 if (result) {
352 if (strcmp(iter->rev[0].date, result->rev[0].date) > 0) {
353 /* iter is newer than current result */
354 result = iter;
355 }
356 } else {
357 result = iter;
358 }
359 }
360 }
361
362 return result;
363}
364
Michal Vasko99b0aad2015-12-01 12:28:51 +0100365API void
Michal Vaskoca28aab2017-01-13 13:50:12 +0100366ly_ctx_set_module_imp_clb(struct ly_ctx *ctx, ly_module_imp_clb clb, void *user_data)
Michal Vasko82465962015-11-10 11:03:11 +0100367{
Michal Vaskof53187d2017-01-13 13:23:14 +0100368 ctx->imp_clb = clb;
369 ctx->imp_clb_data = user_data;
Michal Vasko99b0aad2015-12-01 12:28:51 +0100370}
371
Michal Vaskof53187d2017-01-13 13:23:14 +0100372API ly_module_imp_clb
Michal Vaskoca28aab2017-01-13 13:50:12 +0100373ly_ctx_get_module_imp_clb(const struct ly_ctx *ctx, void **user_data)
Michal Vasko99b0aad2015-12-01 12:28:51 +0100374{
Radek Krejciee554172016-12-14 10:29:06 +0100375 if (!ctx) {
376 ly_errno = LY_EINVAL;
377 return NULL;
378 }
379
Michal Vasko99b0aad2015-12-01 12:28:51 +0100380 if (user_data) {
Michal Vaskof53187d2017-01-13 13:23:14 +0100381 *user_data = ctx->imp_clb_data;
Michal Vasko99b0aad2015-12-01 12:28:51 +0100382 }
Michal Vaskof53187d2017-01-13 13:23:14 +0100383 return ctx->imp_clb;
384}
385
386API void
Michal Vaskoca28aab2017-01-13 13:50:12 +0100387ly_ctx_set_module_data_clb(struct ly_ctx *ctx, ly_module_data_clb clb, void *user_data)
Michal Vaskof53187d2017-01-13 13:23:14 +0100388{
389 ctx->data_clb = clb;
390 ctx->data_clb_data = user_data;
391}
392
393API ly_module_data_clb
Michal Vaskoca28aab2017-01-13 13:50:12 +0100394ly_ctx_get_module_data_clb(const struct ly_ctx *ctx, void **user_data)
Michal Vaskof53187d2017-01-13 13:23:14 +0100395{
396 if (user_data) {
397 *user_data = ctx->data_clb_data;
398 }
399 return ctx->data_clb;
Michal Vasko99b0aad2015-12-01 12:28:51 +0100400}
401
Radek Krejcibf4e4652016-10-21 15:44:13 +0200402const struct lys_module *
Michal Vasko84475152016-07-25 16:16:25 +0200403ly_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 +0200404 int implement, struct unres_schema *unres)
Michal Vasko99b0aad2015-12-01 12:28:51 +0100405{
Radek Krejcibf4e4652016-10-21 15:44:13 +0200406 const struct lys_module *mod;
Michal Vasko99b0aad2015-12-01 12:28:51 +0100407 char *module_data;
Radek Krejci03203412016-06-23 15:20:53 +0200408 int i;
Michal Vaskod3e975b2016-03-03 15:40:21 +0100409 void (*module_data_free)(void *module_data) = NULL;
Michal Vasko99b0aad2015-12-01 12:28:51 +0100410 LYS_INFORMAT format = LYS_IN_UNKNOWN;
Michal Vasko82465962015-11-10 11:03:11 +0100411
Michal Vasko84475152016-07-25 16:16:25 +0200412 if (!module) {
Radek Krejcibf4e4652016-10-21 15:44:13 +0200413 /* exception for internal modules */
Michal Vasko84475152016-07-25 16:16:25 +0200414 for (i = 0; i < INTERNAL_MODULES_COUNT; i++) {
415 if (ly_strequal(name, internal_modules[i].name, 0)) {
416 if (!revision || ly_strequal(revision, internal_modules[i].revision, 0)) {
417 /* return internal module */
418 return (struct lys_module *)ly_ctx_get_module(ctx, name, revision);
419 }
Radek Krejci03203412016-06-23 15:20:53 +0200420 }
421 }
Radek Krejcibf4e4652016-10-21 15:44:13 +0200422 if (revision) {
Radek Krejci0ec51da2016-12-14 16:42:03 +0100423 /* try to get the schema with the specific revision from the context,
424 * include the disabled modules in the search to avoid their duplication,
425 * they are enabled by the subsequent call to lys_set_implemented() */
426 for (i = INTERNAL_MODULES_COUNT, mod = NULL; i < ctx->models.used; i++) {
427 mod = ctx->models.list[i]; /* shortcut */
428 if (ly_strequal(name, mod->name, 0) && mod->rev_size && !strcmp(revision, mod->rev[0].date)) {
429 break;
430 }
431 mod = NULL;
432 }
Radek Krejcibf4e4652016-10-21 15:44:13 +0200433 if (mod) {
434 /* we get such a module, make it implemented */
435 if (lys_set_implemented(mod)) {
436 /* the schema cannot be implemented */
437 mod = NULL;
438 }
439 return mod;
440 }
441 }
Radek Krejci03203412016-06-23 15:20:53 +0200442 }
443
Michal Vaskof53187d2017-01-13 13:23:14 +0100444 if (ctx->imp_clb) {
Michal Vasko84475152016-07-25 16:16:25 +0200445 if (module) {
446 mod = lys_main_module(module);
Michal Vaskof53187d2017-01-13 13:23:14 +0100447 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 +0200448 } else {
Michal Vaskof53187d2017-01-13 13:23:14 +0100449 module_data = ctx->imp_clb(name, revision, NULL, NULL, ctx->imp_clb_data, &format, &module_data_free);
Michal Vasko84475152016-07-25 16:16:25 +0200450 }
Michal Vasko99b0aad2015-12-01 12:28:51 +0100451 if (!module_data) {
Radek Krejcibf4e4652016-10-21 15:44:13 +0200452 if (module || revision) {
453 /* we already know that the specified revision is not present in context, and we have no other
454 * option in case of submodules */
455 LOGERR(LY_ESYS, "User module retrieval callback failed!");
456 return NULL;
457 } else {
458 /* get the newest revision from the context */
Radek Krejci0ec51da2016-12-14 16:42:03 +0100459 mod = ly_ctx_get_module_by(ctx, name, offsetof(struct lys_module, name), revision, 1);
460 if (mod && mod->disabled) {
461 /* enable the required module */
462 lys_set_enabled(mod);
463 }
464 return mod;
Radek Krejcibf4e4652016-10-21 15:44:13 +0200465 }
Michal Vasko82465962015-11-10 11:03:11 +0100466 }
Michal Vasko84475152016-07-25 16:16:25 +0200467
468 if (module) {
469 mod = (struct lys_module *)lys_submodule_parse(module, module_data, format, unres);
470 } else {
471 mod = (struct lys_module *)lys_parse_mem(ctx, module_data, format);
472 }
473
Michal Vasko99b0aad2015-12-01 12:28:51 +0100474 if (module_data_free) {
475 module_data_free(module_data);
Michal Vasko82465962015-11-10 11:03:11 +0100476 }
Michal Vasko99b0aad2015-12-01 12:28:51 +0100477 } else {
Michal Vasko58e5f3e2016-07-28 11:06:34 +0200478 mod = lyp_search_file(ctx, module, name, revision, implement, unres);
Michal Vasko82465962015-11-10 11:03:11 +0100479 }
480
Michal Vasko84475152016-07-25 16:16:25 +0200481 return mod;
482}
483
484API const struct lys_module *
485ly_ctx_load_module(struct ly_ctx *ctx, const char *name, const char *revision)
486{
487 if (!ctx || !name) {
488 ly_errno = LY_EINVAL;
489 return NULL;
490 }
491
Michal Vasko58e5f3e2016-07-28 11:06:34 +0200492 return ly_ctx_load_sub_module(ctx, NULL, name, revision, 1, NULL);
Michal Vasko82465962015-11-10 11:03:11 +0100493}
494
Radek Krejci85a54be2016-10-20 12:39:56 +0200495/*
496 * mods - set of removed modules, if NULL all modules are supposed to be removed so any backlink is invalid
497 */
498static int
499ctx_modules_maintain_backlinks(struct ly_ctx *ctx, struct ly_set *mods)
500{
501 int o;
502 uint8_t j;
503 unsigned int u, v;
504 struct lys_module *mod;
505 struct lys_node *elem, *next;
506 struct lys_node_leaf *leaf;
507
508 /* maintain backlinks (start with internal ietf-yang-library which have leafs as possible targets of leafrefs */
509 for (o = INTERNAL_MODULES_COUNT - 1; o < ctx->models.used; o++) {
510 mod = ctx->models.list[o]; /* shortcut */
511
512 /* 1) features */
513 for (j = 0; j < mod->features_size; j++) {
514 if (!mod->features[j].depfeatures) {
515 continue;
516 }
517 for (v = 0; v < mod->features[j].depfeatures->number; v++) {
518 if (!mods || ly_set_contains(mods, ((struct lys_feature *)mod->features[j].depfeatures->set.g[v])->module) != -1) {
519 /* depending feature is in module to remove */
520 ly_set_rm_index(mod->features[j].depfeatures, v);
521 v--;
522 }
523 }
524 if (!mod->features[j].depfeatures->number) {
525 /* all backlinks removed */
526 ly_set_free(mod->features[j].depfeatures);
527 mod->features[j].depfeatures = NULL;
528 }
529 }
530 /* identities */
531 for (u = 0; u < mod->ident_size; u++) {
532 if (!mod->ident[u].der) {
533 continue;
534 }
535 for (v = 0; v < mod->ident[u].der->number; v++) {
536 if (!mods || ly_set_contains(mods, ((struct lys_ident *)mod->ident[u].der->set.g[v])->module) != -1) {
537 /* derived identity is in module to remove */
538 ly_set_rm_index(mod->ident[u].der, v);
539 v--;
540 }
541 }
542 if (!mod->ident[u].der->number) {
543 /* all backlinks removed */
544 ly_set_free(mod->ident[u].der);
545 mod->ident[u].der = NULL;
546 }
547 }
548
549 /* leafrefs */
550 for (elem = next = mod->data; elem; elem = next) {
551 if (elem->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
552 leaf = (struct lys_node_leaf *)elem; /* shortcut */
553 if (leaf->backlinks) {
554 if (!mods) {
555 /* remove all backlinks */
556 ly_set_free(leaf->backlinks);
557 leaf->backlinks = NULL;
558 } else {
559 for (v = 0; v < leaf->backlinks->number; v++) {
560 if (ly_set_contains(mods, leaf->backlinks->set.s[v]->module) != -1) {
561 /* derived identity is in module to remove */
562 ly_set_rm_index(leaf->backlinks, v);
563 v--;
564 }
565 }
566 if (!leaf->backlinks->number) {
567 /* all backlinks removed */
568 ly_set_free(leaf->backlinks);
569 leaf->backlinks = NULL;
570 }
571 }
572 }
573 }
574
575 /* select next element to process */
576 next = elem->child;
577 /* child exception for leafs, leaflists, anyxml and groupings */
578 if (elem->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA | LYS_GROUPING)) {
579 next = NULL;
580 }
581 if (!next) {
582 /* no children, try siblings */
583 next = elem->next;
584 }
585 while (!next) {
586 /* parent is already processed, go to its sibling */
587 elem = lys_parent(elem);
588 if (!elem) {
589 /* we are done, no next element to process */
590 break;
591 }
592 /* no siblings, go back through parents */
593 next = elem->next;
594 }
595 }
596 }
597
598 return EXIT_SUCCESS;
599}
600
Radek Krejci8c107fe2016-10-17 16:00:18 +0200601API int
Radek Krejci0ec51da2016-12-14 16:42:03 +0100602lys_set_disabled(const struct lys_module *module)
603{
604 struct ly_ctx *ctx; /* shortcut */
605 struct lys_module *mod;
606 struct ly_set *mods;
607 uint8_t j, imported;
608 int i, o;
609 unsigned int u;
610
611 if (!module) {
612 ly_errno = LY_EINVAL;
613 return EXIT_FAILURE;
614 } else if (module->disabled) {
615 /* already disabled module */
616 return EXIT_SUCCESS;
617 }
618 mod = (struct lys_module *)module;
619 ctx = mod->ctx;
620
621 /* avoid disabling internal modules */
622 for (i = 0; i < INTERNAL_MODULES_COUNT; i++) {
623 if (mod == ctx->models.list[i]) {
624 LOGERR(LY_EINVAL, "Internal module \"%s\" cannot be removed.", mod->name);
625 return EXIT_FAILURE;
626 }
627 }
628
629 /* disable the module */
630 mod->disabled = 1;
631
632 /* get the complete list of modules to disable because of dependencies,
633 * we are going also to disable all the imported (not implemented) modules
634 * that are not used in any other module */
635 mods = ly_set_new();
636 ly_set_add(mods, mod, 0);
637checkdependency:
638 for (i = INTERNAL_MODULES_COUNT; i < ctx->models.used; i++) {
639 mod = ctx->models.list[i]; /* shortcut */
640 if (mod->disabled) {
641 /* skip the already disabled modules */
642 continue;
643 }
644
645 /* check depndency of imported modules */
646 for (j = 0; j < mod->imp_size; j++) {
647 for (u = 0; u < mods->number; u++) {
648 if (mod->imp[j].module == mods->set.g[u]) {
649 /* module is importing some module to disable, so it must be also disabled */
650 mod->disabled = 1;
651 ly_set_add(mods, mod, 0);
652 /* we have to start again because some of the already checked modules can
653 * depend on the one we have just decided to disable */
654 goto checkdependency;
655 }
656 }
657 }
658 /* check if the imported module is used in any module supposed to be kept */
659 if (!mod->implemented) {
660 imported = 0;
661 for (o = INTERNAL_MODULES_COUNT; o < ctx->models.used; o++) {
662 if (ctx->models.list[o]->disabled) {
663 /* skip modules already disabled */
664 continue;
665 }
666 for (j = 0; j < ctx->models.list[o]->imp_size; j++) {
667 if (ctx->models.list[o]->imp[j].module == mod) {
668 /* the module is used in some other module not yet selected to be disabled */
669 imported = 1;
670 goto imported;
671 }
672 }
673 }
674imported:
675 if (!imported) {
676 /* module is not implemented and neither imported by any other module in context
677 * which is supposed to be kept enabled after this operation, so we are going to disable also
678 * this module */
679 mod->disabled = 1;
680 ly_set_add(mods, mod, 0);
681 /* we have to start again, this time not because other module can depend on this one
682 * (we know that there is no such module), but because the module can import module
683 * that could became useless. If there are no imports, we can continue */
684 if (mod->imp_size) {
685 goto checkdependency;
686 }
687 }
688 }
689 }
690
691 /* before removing applied deviations, augments and updating leafrefs, we have to enable the modules
692 * to disable to allow all that operations */
693 for (u = 0; u < mods->number; u++) {
694 ((struct lys_module *)mods->set.g[u])->disabled = 0;
695 }
696
697 /* maintain backlinks (start with internal ietf-yang-library which have leafs as possible targets of leafrefs */
698 ctx_modules_maintain_backlinks(ctx, mods);
699
700 /* remove the applied deviations and augments */
701 for (u = 0; u < mods->number; u++) {
702 lys_sub_module_remove_devs_augs((struct lys_module *)mods->set.g[u]);
703 }
704
705 /* now again disable the modules to disable */
706 for (u = 0; u < mods->number; u++) {
707 ((struct lys_module *)mods->set.g[u])->disabled = 1;
708 }
709
710 /* free the set */
711 ly_set_free(mods);
712
713 /* update the module-set-id */
714 ctx->models.module_set_id++;
715
716 return EXIT_SUCCESS;
717}
718
719static void
720lys_set_enabled_(struct ly_set *mods, struct lys_module *mod)
721{
722 unsigned int i;
723
724 ly_set_add(mods, mod, 0);
725 mod->disabled = 0;
726
727 /* go recursively */
728 for (i = 0; i < mod->imp_size; i++) {
729 if (!mod->imp[i].module->disabled) {
730 continue;
731 }
732
733 lys_set_enabled_(mods, mod->imp[i].module);
734 }
735}
736
737API int
738lys_set_enabled(const struct lys_module *module)
739{
740 struct ly_ctx *ctx; /* shortcut */
741 struct lys_module *mod;
742 struct ly_set *mods, *disabled;
743 int i;
744 unsigned int u, v;
745
746 if (!module) {
747 ly_errno = LY_EINVAL;
748 return EXIT_FAILURE;
749 } else if (!module->disabled) {
750 /* already enabled module */
751 return EXIT_SUCCESS;
752 }
753 mod = (struct lys_module *)module;
754 ctx = mod->ctx;
755
756 /* avoid disabling internal modules */
757 for (i = 0; i < INTERNAL_MODULES_COUNT; i++) {
758 if (mod == ctx->models.list[i]) {
759 LOGERR(LY_EINVAL, "Internal module \"%s\" cannot be removed.", mod->name);
760 return EXIT_FAILURE;
761 }
762 }
763
764 mods = ly_set_new();
765 disabled = ly_set_new();
766
767 /* enable the module, including its dependencies */
768 lys_set_enabled_(mods, mod);
769
770 /* we will go through the all disabled modules in the context, if the module has no dependency (import)
771 * that is still disabled AND at least one of its imported module is from the set we are enabling now,
772 * it is going to be also enabled. This way we try to revert everething that was possibly done by
773 * lys_set_disabled(). */
774checkdependency:
775 for (i = INTERNAL_MODULES_COUNT; i < ctx->models.used; i++) {
776 mod = ctx->models.list[i]; /* shortcut */
777 if (!mod->disabled || ly_set_contains(disabled, mod) != -1) {
778 /* skip the enabled modules */
779 continue;
780 }
781
782 /* check imported modules */
783 for (u = 0; u < mod->imp_size; u++) {
784 if (mod->imp[u].module->disabled) {
785 /* it has disabled dependency so it must stay disabled */
786 break;
787 }
788 }
789 if (u < mod->imp_size) {
790 /* it has disabled dependency, continue with the next module in the context */
791 continue;
792 }
793
794 /* get know if at least one of the imported modules is being enabled this time */
795 for (u = 0; u < mod->imp_size; u++) {
796 for (v = 0; v < mods->number; v++) {
797 if (mod->imp[u].module == mods->set.g[v]) {
798 /* yes, it is, so they are connected and we are going to enable it as well,
799 * it is not necessary to call recursive lys_set_enable_() because we already
800 * know that there is no disabled import to enable */
801 mod->disabled = 0;
802 ly_set_add(mods, mod, 0);
803 /* we have to start again because some of the already checked modules can
804 * depend on the one we have just decided to enable */
805 goto checkdependency;
806 }
807 }
808 }
809
810 /* this module is disabled, but it does not depend on any other disabled module and none
811 * of its imports was not enabled in this call. No future enabling of the disabled module
812 * will change this so we can remember the module and skip it next time we will have to go
813 * through the all context because of the checkdependency goto.
814 */
815 ly_set_add(disabled, mod, 0);
816 }
817
818 /* maintain backlinks (start with internal ietf-yang-library which have leafs as possible targets of leafrefs */
819 ctx_modules_maintain_backlinks(ctx, mods);
820
821 /* re-apply the deviations and augments */
822 for (v = 0; v < mods->number; v++) {
823 lys_sub_module_apply_devs_augs((struct lys_module *)mods->set.g[v]);
824 }
825
826 /* free the sets */
827 ly_set_free(mods);
828 ly_set_free(disabled);
829
830 /* update the module-set-id */
831 ctx->models.module_set_id++;
832
833 return EXIT_SUCCESS;
834}
835
836API int
837ly_ctx_remove_module(const struct lys_module *module,
Radek Krejci8c107fe2016-10-17 16:00:18 +0200838 void (*private_destructor)(const struct lys_node *node, void *priv))
839{
Radek Krejci0ec51da2016-12-14 16:42:03 +0100840 struct ly_ctx *ctx; /* shortcut */
Radek Krejci8c107fe2016-10-17 16:00:18 +0200841 struct lys_module *mod = NULL;
842 struct ly_set *mods;
843 uint8_t j, imported;
844 int i, o;
845 unsigned int u;
846
Radek Krejci0ec51da2016-12-14 16:42:03 +0100847 if (!module) {
Radek Krejci8c107fe2016-10-17 16:00:18 +0200848 ly_errno = LY_EINVAL;
849 return EXIT_FAILURE;
850 }
851
Radek Krejci0ec51da2016-12-14 16:42:03 +0100852 mod = (struct lys_module *)module;
853 ctx = mod->ctx;
854
Radek Krejci8c107fe2016-10-17 16:00:18 +0200855 /* avoid removing internal modules ... */
856 for (i = 0; i < INTERNAL_MODULES_COUNT; i++) {
857 if (mod == ctx->models.list[i]) {
Radek Krejci0ec51da2016-12-14 16:42:03 +0100858 LOGERR(LY_EINVAL, "Internal module \"%s\" cannot be removed.", mod->name);
Radek Krejci8c107fe2016-10-17 16:00:18 +0200859 return EXIT_FAILURE;
860 }
861 }
862 /* ... and hide the module from the further processing of the context modules list */
863 for (i = INTERNAL_MODULES_COUNT; i < ctx->models.used; i++) {
864 if (mod == ctx->models.list[i]) {
865 ctx->models.list[i] = NULL;
866 break;
867 }
868 }
869
870 /* get the complete list of modules to remove because of dependencies,
871 * we are going also to remove all the imported (not implemented) modules
872 * that are not used in any other module */
873 mods = ly_set_new();
874 ly_set_add(mods, mod, 0);
875checkdependency:
876 for (i = INTERNAL_MODULES_COUNT; i < ctx->models.used; i++) {
877 mod = ctx->models.list[i]; /* shortcut */
878 if (!mod) {
879 /* skip modules already selected for removing */
880 continue;
881 }
882
883 /* check depndency of imported modules */
884 for (j = 0; j < mod->imp_size; j++) {
885 for (u = 0; u < mods->number; u++) {
886 if (mod->imp[j].module == mods->set.g[u]) {
887 /* module is importing some module to remove, so it must be also removed */
888 ly_set_add(mods, mod, 0);
889 ctx->models.list[i] = NULL;
890 /* we have to start again because some of the already checked modules can
891 * depend on the one we have just decided to remove */
892 goto checkdependency;
893 }
894 }
895 }
896 /* check if the imported module is used in any module supposed to be kept */
897 if (!mod->implemented) {
898 imported = 0;
899 for (o = INTERNAL_MODULES_COUNT; o < ctx->models.used; o++) {
900 if (!ctx->models.list[o]) {
901 /* skip modules already selected for removing */
902 continue;
903 }
904 for (j = 0; j < ctx->models.list[o]->imp_size; j++) {
905 if (ctx->models.list[o]->imp[j].module == mod) {
906 /* the module is used in some other module not yet selected to be deleted */
907 imported = 1;
908 goto imported;
909 }
910 }
911 }
912imported:
913 if (!imported) {
914 /* module is not implemented and neither imported by any other module in context
915 * which is supposed to be kept after this operation, so we are going to remove also
916 * this useless module */
917 ly_set_add(mods, mod, 0);
918 ctx->models.list[i] = NULL;
919 /* we have to start again, this time not because other module can depend on this one
Radek Krejci0ec51da2016-12-14 16:42:03 +0100920 * (we know that there is no such module), but because the module can import module
Radek Krejci8c107fe2016-10-17 16:00:18 +0200921 * that could became useless. If there are no imports, we can continue */
922 if (mod->imp_size) {
923 goto checkdependency;
924 }
925 }
926 }
927 }
928
Radek Krejci8c107fe2016-10-17 16:00:18 +0200929
930 /* consolidate the modules list */
931 for (i = o = INTERNAL_MODULES_COUNT; i < ctx->models.used; i++) {
932 if (ctx->models.list[o]) {
933 /* used cell */
934 o++;
935 } else {
936 /* the current output cell is empty, move here an input cell */
937 ctx->models.list[o] = ctx->models.list[i];
938 ctx->models.list[i] = NULL;
939 }
940 }
941 /* get the last used cell to get know the number of used */
942 while (!ctx->models.list[o]) {
943 o--;
944 }
945 ctx->models.used = o + 1;
946 ctx->models.module_set_id++;
947
Radek Krejci85a54be2016-10-20 12:39:56 +0200948 /* maintain backlinks (start with internal ietf-yang-library which have leafs as possible targets of leafrefs */
949 ctx_modules_maintain_backlinks(ctx, mods);
950
951 /* free the modules */
952 for (u = 0; u < mods->number; u++) {
Radek Krejcib2541a32016-12-12 16:45:57 +0100953 /* remove the applied deviations and augments */
954 lys_sub_module_remove_devs_augs((struct lys_module *)mods->set.g[u]);
Radek Krejci85a54be2016-10-20 12:39:56 +0200955 /* remove the module */
956 lys_free((struct lys_module *)mods->set.g[u], private_destructor, 0);
957 }
958 ly_set_free(mods);
959
Radek Krejci8c107fe2016-10-17 16:00:18 +0200960 return EXIT_SUCCESS;
961}
962
Radek Krejci85a54be2016-10-20 12:39:56 +0200963API void
964ly_ctx_clean(struct ly_ctx *ctx, void (*private_destructor)(const struct lys_node *node, void *priv))
965{
966 int i;
967
968 if (!ctx) {
969 return;
970 }
971
972 /* models list */
973 for (i = INTERNAL_MODULES_COUNT; i < ctx->models.used; ++i) {
974 lys_free(ctx->models.list[i], private_destructor, 0);
975 ctx->models.list[i] = NULL;
976 }
977 ctx->models.used = INTERNAL_MODULES_COUNT;
978 ctx->models.module_set_id++;
979
980 /* maintain backlinks (actually done only with ietf-yang-library since its leafs cna be target of leafref) */
981 ctx_modules_maintain_backlinks(ctx, NULL);
982}
983
Michal Vaskod7957c02016-04-01 10:27:26 +0200984API const struct lys_module *
985ly_ctx_get_module_iter(const struct ly_ctx *ctx, uint32_t *idx)
986{
987 if (!ctx || !idx) {
988 ly_errno = LY_EINVAL;
989 return NULL;
990 }
991
Radek Krejci0ec51da2016-12-14 16:42:03 +0100992 for ( ; *idx < (unsigned)ctx->models.used; (*idx)++) {
993 if (!ctx->models.list[(*idx)]->disabled) {
994 return ctx->models.list[(*idx)++];
995 }
996 }
997
998 return NULL;
999}
1000
1001API const struct lys_module *
1002ly_ctx_get_disabled_module_iter(const struct ly_ctx *ctx, uint32_t *idx)
1003{
1004 if (!ctx || !idx) {
1005 ly_errno = LY_EINVAL;
Michal Vaskod7957c02016-04-01 10:27:26 +02001006 return NULL;
1007 }
1008
Radek Krejci0ec51da2016-12-14 16:42:03 +01001009 for ( ; *idx < (unsigned)ctx->models.used; (*idx)++) {
1010 if (ctx->models.list[(*idx)]->disabled) {
1011 return ctx->models.list[(*idx)++];
1012 }
1013 }
1014
1015 return NULL;
Michal Vaskod7957c02016-04-01 10:27:26 +02001016}
1017
Michal Vasko209a6222015-10-16 09:51:07 +02001018static int
1019ylib_feature(struct lyd_node *parent, struct lys_module *cur_mod)
1020{
1021 int i, j;
1022
1023 /* module features */
1024 for (i = 0; i < cur_mod->features_size; ++i) {
1025 if (!(cur_mod->features[i].flags & LYS_FENABLED)) {
1026 continue;
1027 }
1028
Michal Vasko3e671b52015-10-23 16:23:15 +02001029 if (!lyd_new_leaf(parent, NULL, "feature", cur_mod->features[i].name)) {
Michal Vasko209a6222015-10-16 09:51:07 +02001030 return EXIT_FAILURE;
1031 }
1032 }
1033
1034 /* submodule features */
Radek Krejcic071c542016-01-27 14:57:51 +01001035 for (i = 0; i < cur_mod->inc_size && cur_mod->inc[i].submodule; ++i) {
Michal Vasko209a6222015-10-16 09:51:07 +02001036 for (j = 0; j < cur_mod->inc[i].submodule->features_size; ++j) {
1037 if (!(cur_mod->inc[i].submodule->features[j].flags & LYS_FENABLED)) {
1038 continue;
1039 }
1040
Michal Vasko3e671b52015-10-23 16:23:15 +02001041 if (!lyd_new_leaf(parent, NULL, "feature", cur_mod->inc[i].submodule->features[j].name)) {
Michal Vasko209a6222015-10-16 09:51:07 +02001042 return EXIT_FAILURE;
1043 }
1044 }
1045 }
1046
1047 return EXIT_SUCCESS;
1048}
1049
1050static int
Michal Vaskoff006c12016-02-17 11:15:19 +01001051ylib_deviation(struct lyd_node *parent, struct lys_module *cur_mod)
Michal Vasko97d8c6d2016-02-12 11:05:48 +01001052{
Michal Vasko89563fc2016-07-28 16:19:35 +02001053 uint32_t i = 0, j;
1054 const struct lys_module *mod;
Michal Vasko209a6222015-10-16 09:51:07 +02001055 struct lyd_node *cont;
Michal Vasko89563fc2016-07-28 16:19:35 +02001056 const char *ptr;
Michal Vasko209a6222015-10-16 09:51:07 +02001057
Michal Vasko89563fc2016-07-28 16:19:35 +02001058 if (cur_mod->deviated) {
1059 while ((mod = ly_ctx_get_module_iter(cur_mod->ctx, &i))) {
1060 if (mod == cur_mod) {
1061 continue;
Michal Vasko209a6222015-10-16 09:51:07 +02001062 }
Michal Vasko209a6222015-10-16 09:51:07 +02001063
Michal Vasko89563fc2016-07-28 16:19:35 +02001064 for (j = 0; j < mod->deviation_size; ++j) {
1065 ptr = strstr(mod->deviation[j].target_name, cur_mod->name);
1066 if (ptr && ptr[strlen(cur_mod->name)] == ':') {
1067 cont = lyd_new(parent, NULL, "deviation");
1068 if (!cont) {
1069 return EXIT_FAILURE;
1070 }
1071
1072 if (!lyd_new_leaf(cont, NULL, "name", mod->name)) {
1073 return EXIT_FAILURE;
1074 }
1075 if (!lyd_new_leaf(cont, NULL, "revision", (mod->rev_size ? mod->rev[0].date : ""))) {
1076 return EXIT_FAILURE;
1077 }
Michal Vasko0c2215b2016-08-25 14:18:43 +02001078
1079 break;
Michal Vasko89563fc2016-07-28 16:19:35 +02001080 }
Michal Vasko209a6222015-10-16 09:51:07 +02001081 }
1082 }
1083 }
1084
1085 return EXIT_SUCCESS;
1086}
1087
1088static int
1089ylib_submodules(struct lyd_node *parent, struct lys_module *cur_mod)
1090{
1091 int i;
Radek Krejcia77904e2016-02-25 16:23:45 +01001092 char *str;
Radek Krejcid9723912016-09-16 17:06:06 +02001093 struct lyd_node *item;
Michal Vasko209a6222015-10-16 09:51:07 +02001094
Radek Krejcic071c542016-01-27 14:57:51 +01001095 for (i = 0; i < cur_mod->inc_size && cur_mod->inc[i].submodule; ++i) {
Radek Krejcid9723912016-09-16 17:06:06 +02001096 item = lyd_new(parent, NULL, "submodule");
Radek Krejci6e05cea2015-12-10 16:34:37 +01001097 if (!item) {
Michal Vasko209a6222015-10-16 09:51:07 +02001098 return EXIT_FAILURE;
1099 }
1100
Radek Krejci6e05cea2015-12-10 16:34:37 +01001101 if (!lyd_new_leaf(item, NULL, "name", cur_mod->inc[i].submodule->name)) {
Michal Vasko209a6222015-10-16 09:51:07 +02001102 return EXIT_FAILURE;
1103 }
Radek Krejci6e05cea2015-12-10 16:34:37 +01001104 if (!lyd_new_leaf(item, NULL, "revision", (cur_mod->inc[i].submodule->rev_size ?
Michal Vasko3e671b52015-10-23 16:23:15 +02001105 cur_mod->inc[i].submodule->rev[0].date : ""))) {
Michal Vasko209a6222015-10-16 09:51:07 +02001106 return EXIT_FAILURE;
1107 }
Radek Krejcia77904e2016-02-25 16:23:45 +01001108 if (cur_mod->inc[i].submodule->filepath) {
Radek Krejci95aa2012016-03-03 11:21:09 +01001109 if (asprintf(&str, "file://%s", cur_mod->inc[i].submodule->filepath) == -1) {
Radek Krejcia77904e2016-02-25 16:23:45 +01001110 LOGMEM;
1111 return EXIT_FAILURE;
Radek Krejci6e65af92016-03-07 12:48:19 +01001112 } else if (!lyd_new_leaf(item, NULL, "schema", str)) {
Radek Krejci19f9ede2016-02-25 16:29:21 +01001113 free(str);
Radek Krejcia77904e2016-02-25 16:23:45 +01001114 return EXIT_FAILURE;
1115 }
Radek Krejci19f9ede2016-02-25 16:29:21 +01001116 free(str);
Michal Vasko209a6222015-10-16 09:51:07 +02001117 }
1118 }
1119
1120 return EXIT_SUCCESS;
1121}
1122
1123API struct lyd_node *
1124ly_ctx_info(struct ly_ctx *ctx)
1125{
1126 int i;
1127 char id[8];
Radek Krejcia77904e2016-02-25 16:23:45 +01001128 char *str;
Michal Vasko1e62a092015-12-01 12:27:20 +01001129 const struct lys_module *mod;
Michal Vasko209a6222015-10-16 09:51:07 +02001130 struct lyd_node *root, *cont;
1131
Michal Vasko7eccc6c2016-03-24 14:56:33 +01001132 if (!ctx) {
1133 ly_errno = LY_EINVAL;
1134 return NULL;
1135 }
1136
Radek Krejcibd9e8d22016-02-03 14:11:48 +01001137 mod = ly_ctx_get_module(ctx, "ietf-yang-library", IETF_YANG_LIB_REV);
1138 if (!mod || !mod->data) {
1139 LOGINT;
Michal Vasko209a6222015-10-16 09:51:07 +02001140 return NULL;
1141 }
1142
Radek Krejcibd9e8d22016-02-03 14:11:48 +01001143 root = lyd_new(NULL, mod, "modules-state");
Michal Vasko209a6222015-10-16 09:51:07 +02001144 if (!root) {
1145 return NULL;
1146 }
1147
1148 for (i = 0; i < ctx->models.used; ++i) {
Radek Krejci0ec51da2016-12-14 16:42:03 +01001149 if (ctx->models.list[i]->disabled) {
1150 /* skip the disabled modules */
1151 continue;
1152 }
1153
Michal Vasko209a6222015-10-16 09:51:07 +02001154 cont = lyd_new(root, NULL, "module");
1155 if (!cont) {
1156 lyd_free(root);
1157 return NULL;
1158 }
1159
Michal Vasko3e671b52015-10-23 16:23:15 +02001160 if (!lyd_new_leaf(cont, NULL, "name", ctx->models.list[i]->name)) {
Michal Vasko209a6222015-10-16 09:51:07 +02001161 lyd_free(root);
1162 return NULL;
1163 }
Michal Vasko3e671b52015-10-23 16:23:15 +02001164 if (!lyd_new_leaf(cont, NULL, "revision", (ctx->models.list[i]->rev_size ?
Michal Vasko209a6222015-10-16 09:51:07 +02001165 ctx->models.list[i]->rev[0].date : ""))) {
1166 lyd_free(root);
1167 return NULL;
1168 }
Radek Krejcia77904e2016-02-25 16:23:45 +01001169 if (ctx->models.list[i]->filepath) {
Radek Krejci15412ca2016-03-03 11:16:52 +01001170 if (asprintf(&str, "file://%s", ctx->models.list[i]->filepath) == -1) {
Radek Krejcia77904e2016-02-25 16:23:45 +01001171 LOGMEM;
1172 lyd_free(root);
1173 return NULL;
1174 } else if (!lyd_new_leaf(cont, NULL, "schema", str)) {
Radek Krejci19f9ede2016-02-25 16:29:21 +01001175 free(str);
Radek Krejcia77904e2016-02-25 16:23:45 +01001176 lyd_free(root);
1177 return NULL;
1178 }
Radek Krejci19f9ede2016-02-25 16:29:21 +01001179 free(str);
Michal Vasko209a6222015-10-16 09:51:07 +02001180 }
Michal Vasko3e671b52015-10-23 16:23:15 +02001181 if (!lyd_new_leaf(cont, NULL, "namespace", ctx->models.list[i]->ns)) {
Michal Vasko209a6222015-10-16 09:51:07 +02001182 lyd_free(root);
1183 return NULL;
1184 }
1185 if (ylib_feature(cont, ctx->models.list[i])) {
1186 lyd_free(root);
1187 return NULL;
1188 }
Michal Vaskoff006c12016-02-17 11:15:19 +01001189 if (ylib_deviation(cont, ctx->models.list[i])) {
Michal Vasko209a6222015-10-16 09:51:07 +02001190 lyd_free(root);
1191 return NULL;
1192 }
1193 if (ctx->models.list[i]->implemented
Radek Krejcibd9e8d22016-02-03 14:11:48 +01001194 && !lyd_new_leaf(cont, NULL, "conformance-type", "implement")) {
Michal Vasko209a6222015-10-16 09:51:07 +02001195 lyd_free(root);
1196 return NULL;
1197 }
1198 if (!ctx->models.list[i]->implemented
Radek Krejcibd9e8d22016-02-03 14:11:48 +01001199 && !lyd_new_leaf(cont, NULL, "conformance-type", "import")) {
Michal Vasko209a6222015-10-16 09:51:07 +02001200 lyd_free(root);
1201 return NULL;
1202 }
1203 if (ylib_submodules(cont, ctx->models.list[i])) {
1204 lyd_free(root);
1205 return NULL;
1206 }
1207 }
1208
1209 sprintf(id, "%u", ctx->models.module_set_id);
Michal Vasko3e671b52015-10-23 16:23:15 +02001210 if (!lyd_new_leaf(root, mod, "module-set-id", id)) {
Michal Vasko209a6222015-10-16 09:51:07 +02001211 lyd_free(root);
1212 return NULL;
1213 }
1214
Michal Vaskocdb90172016-09-13 09:34:36 +02001215 if (lyd_validate(&root, LYD_OPT_NOSIBLINGS, NULL)) {
Michal Vasko209a6222015-10-16 09:51:07 +02001216 lyd_free(root);
1217 return NULL;
1218 }
1219
1220 return root;
1221}
Michal Vasko3edeaf72016-02-11 13:17:43 +01001222
1223API const struct lys_node *
Michal Vasko3547c532016-03-14 09:40:50 +01001224ly_ctx_get_node(struct ly_ctx *ctx, const struct lys_node *start, const char *nodeid)
Michal Vasko3edeaf72016-02-11 13:17:43 +01001225{
Michal Vaskoe733d682016-03-14 09:08:27 +01001226 const struct lys_node *node;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001227
Michal Vasko3547c532016-03-14 09:40:50 +01001228 if (!ctx || !nodeid || ((nodeid[0] != '/') && !start)) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001229 ly_errno = LY_EINVAL;
1230 return NULL;
1231 }
1232
Michal Vaskoe733d682016-03-14 09:08:27 +01001233 /* sets error and everything */
Michal Vasko8d26e5c2016-09-08 10:03:49 +02001234 node = resolve_json_nodeid(nodeid, ctx, start);
Michal Vasko3edeaf72016-02-11 13:17:43 +01001235
Michal Vaskoe733d682016-03-14 09:08:27 +01001236 return node;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001237}