blob: 356b5dc250cc9539c16a93463b2d65983ebf862f [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{
182 struct lys_submodule *result;
183 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;
193 if (result && ly_strequal(submodule, result->name, 0)) {
194 return result;
195 }
196 }
197
198 return NULL;
199}
200
201API const struct lys_submodule *
Michal Vaskof6d94c62016-04-05 11:21:54 +0200202ly_ctx_get_submodule(const struct ly_ctx *ctx, const char *module, const char *revision, const char *submodule,
203 const char *sub_revision)
Radek Krejciefaeba32015-05-27 14:30:57 +0200204{
Radek Krejcie7973552016-03-07 08:12:01 +0100205 const struct lys_module *mainmod;
Michal Vaskof6d94c62016-04-05 11:21:54 +0200206 const struct lys_submodule *ret = NULL, *submod;
207 uint32_t idx = 0;
Radek Krejciefaeba32015-05-27 14:30:57 +0200208
Michal Vaskof6d94c62016-04-05 11:21:54 +0200209 if (!ctx || !submodule || (revision && !module)) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200210 ly_errno = LY_EINVAL;
211 return NULL;
212 }
Radek Krejciefaeba32015-05-27 14:30:57 +0200213
Michal Vaskof6d94c62016-04-05 11:21:54 +0200214 while ((mainmod = ly_ctx_get_module_iter(ctx, &idx))) {
215 if (module && strcmp(mainmod->name, module)) {
216 /* main module name does not match */
217 continue;
218 }
219
220 if (revision && (!mainmod->rev || strcmp(revision, mainmod->rev[0].date))) {
221 /* main module revision does not match */
222 continue;
223 }
224
225 submod = ly_ctx_get_submodule2(mainmod, submodule);
226 if (!submod) {
227 continue;
228 }
229
230 if (!sub_revision) {
231 /* store only if newer */
232 if (ret) {
233 if (submod->rev && (!ret->rev || (strcmp(submod->rev[0].date, ret->rev[0].date) > 0))) {
234 ret = submod;
235 }
236 } else {
237 ret = submod;
238 }
239 } else {
240 /* store only if revision matches, we are done if it does */
241 if (!submod->rev) {
242 continue;
243 } else if (!strcmp(sub_revision, submod->rev[0].date)) {
244 ret = submod;
245 break;
246 }
247 }
Radek Krejcia7533f22016-03-07 07:37:45 +0100248 }
Radek Krejcic071c542016-01-27 14:57:51 +0100249
Michal Vaskof6d94c62016-04-05 11:21:54 +0200250 return ret;
Radek Krejciefaeba32015-05-27 14:30:57 +0200251}
252
Michal Vasko1e62a092015-12-01 12:27:20 +0100253static const struct lys_module *
Radek Krejci0ec51da2016-12-14 16:42:03 +0100254ly_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 +0200255{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200256 int i;
Radek Krejcib8048692015-08-05 13:36:34 +0200257 struct lys_module *result = NULL;
Radek Krejciefaeba32015-05-27 14:30:57 +0200258
Radek Krejcifd4e6e32015-08-10 15:00:51 +0200259 if (!ctx || !key) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200260 ly_errno = LY_EINVAL;
261 return NULL;
262 }
Radek Krejciefaeba32015-05-27 14:30:57 +0200263
Radek Krejcidce51452015-06-16 15:20:08 +0200264 for (i = 0; i < ctx->models.used; i++) {
Radek Krejci0ec51da2016-12-14 16:42:03 +0100265 if (!with_disabled && ctx->models.list[i]->disabled) {
266 /* skip the disabled modules */
267 continue;
268 }
Radek Krejcifd4e6e32015-08-10 15:00:51 +0200269 /* use offset to get address of the pointer to string (char**), remember that offset is in
270 * bytes, so we have to cast the pointer to the module to (char*), finally, we want to have
271 * string not the pointer to string
272 */
273 if (!ctx->models.list[i] || strcmp(key, *(char**)(((char*)ctx->models.list[i]) + offset))) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200274 continue;
275 }
Radek Krejciefaeba32015-05-27 14:30:57 +0200276
Radek Krejcif647e612015-07-30 11:36:07 +0200277 if (!revision) {
278 /* compare revisons and remember the newest one */
279 if (result) {
280 if (!ctx->models.list[i]->rev_size) {
281 /* the current have no revision, keep the previous with some revision */
282 continue;
283 }
284 if (result->rev_size && strcmp(ctx->models.list[i]->rev[0].date, result->rev[0].date) < 0) {
285 /* the previous found matching module has a newer revision */
286 continue;
287 }
288 }
289
290 /* remember the current match and search for newer version */
291 result = ctx->models.list[i];
292 } else {
293 if (ctx->models.list[i]->rev_size && !strcmp(revision, ctx->models.list[i]->rev[0].date)) {
294 /* matching revision */
Michal Vasko97586502015-08-12 14:32:18 +0200295 result = ctx->models.list[i];
296 break;
Radek Krejcif647e612015-07-30 11:36:07 +0200297 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200298 }
299 }
Radek Krejciefaeba32015-05-27 14:30:57 +0200300
Radek Krejcif647e612015-07-30 11:36:07 +0200301 return result;
Radek Krejcifd4e6e32015-08-10 15:00:51 +0200302
303}
304
Michal Vasko1e62a092015-12-01 12:27:20 +0100305API const struct lys_module *
306ly_ctx_get_module_by_ns(const struct ly_ctx *ctx, const char *ns, const char *revision)
Radek Krejcifd4e6e32015-08-10 15:00:51 +0200307{
Radek Krejci0ec51da2016-12-14 16:42:03 +0100308 return ly_ctx_get_module_by(ctx, ns, offsetof(struct lys_module, ns), revision, 0);
Radek Krejcifd4e6e32015-08-10 15:00:51 +0200309}
310
Michal Vasko1e62a092015-12-01 12:27:20 +0100311API const struct lys_module *
312ly_ctx_get_module(const struct ly_ctx *ctx, const char *name, 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, name, offsetof(struct lys_module, name), revision, 0);
Radek Krejcida04f4a2015-05-21 12:54:09 +0200315}
Michal Vasko3ec07dc2015-06-30 15:51:30 +0200316
Radek Krejci21601a32016-03-07 11:39:27 +0100317API const struct lys_module *
318ly_ctx_get_module_older(const struct ly_ctx *ctx, const struct lys_module *module)
319{
320 int i;
321 const struct lys_module *result = NULL, *iter;
322
323 if (!ctx || !module || !module->rev_size) {
324 ly_errno = LY_EINVAL;
325 return NULL;
326 }
327
328
329 for (i = 0; i < ctx->models.used; i++) {
330 iter = ctx->models.list[i];
Radek Krejci0ec51da2016-12-14 16:42:03 +0100331 if (iter->disabled) {
332 /* skip the disabled modules */
333 continue;
334 }
Radek Krejci21601a32016-03-07 11:39:27 +0100335 if (iter == module || !iter->rev_size) {
336 /* iter is the module itself or iter has no revision */
337 continue;
338 }
339 if (!ly_strequal(module->name, iter->name, 0)) {
340 /* different module */
341 continue;
342 }
343 if (strcmp(iter->rev[0].date, module->rev[0].date) < 0) {
344 /* iter is older than module */
345 if (result) {
346 if (strcmp(iter->rev[0].date, result->rev[0].date) > 0) {
347 /* iter is newer than current result */
348 result = iter;
349 }
350 } else {
351 result = iter;
352 }
353 }
354 }
355
356 return result;
357}
358
Michal Vasko99b0aad2015-12-01 12:28:51 +0100359API void
Michal Vaskoca28aab2017-01-13 13:50:12 +0100360ly_ctx_set_module_imp_clb(struct ly_ctx *ctx, ly_module_imp_clb clb, void *user_data)
Michal Vasko82465962015-11-10 11:03:11 +0100361{
Michal Vaskof53187d2017-01-13 13:23:14 +0100362 ctx->imp_clb = clb;
363 ctx->imp_clb_data = user_data;
Michal Vasko99b0aad2015-12-01 12:28:51 +0100364}
365
Michal Vaskof53187d2017-01-13 13:23:14 +0100366API ly_module_imp_clb
Michal Vaskoca28aab2017-01-13 13:50:12 +0100367ly_ctx_get_module_imp_clb(const struct ly_ctx *ctx, void **user_data)
Michal Vasko99b0aad2015-12-01 12:28:51 +0100368{
Radek Krejciee554172016-12-14 10:29:06 +0100369 if (!ctx) {
370 ly_errno = LY_EINVAL;
371 return NULL;
372 }
373
Michal Vasko99b0aad2015-12-01 12:28:51 +0100374 if (user_data) {
Michal Vaskof53187d2017-01-13 13:23:14 +0100375 *user_data = ctx->imp_clb_data;
Michal Vasko99b0aad2015-12-01 12:28:51 +0100376 }
Michal Vaskof53187d2017-01-13 13:23:14 +0100377 return ctx->imp_clb;
378}
379
380API void
Michal Vaskoca28aab2017-01-13 13:50:12 +0100381ly_ctx_set_module_data_clb(struct ly_ctx *ctx, ly_module_data_clb clb, void *user_data)
Michal Vaskof53187d2017-01-13 13:23:14 +0100382{
383 ctx->data_clb = clb;
384 ctx->data_clb_data = user_data;
385}
386
387API ly_module_data_clb
Michal Vaskoca28aab2017-01-13 13:50:12 +0100388ly_ctx_get_module_data_clb(const struct ly_ctx *ctx, void **user_data)
Michal Vaskof53187d2017-01-13 13:23:14 +0100389{
390 if (user_data) {
391 *user_data = ctx->data_clb_data;
392 }
393 return ctx->data_clb;
Michal Vasko99b0aad2015-12-01 12:28:51 +0100394}
395
Radek Krejcibf4e4652016-10-21 15:44:13 +0200396const struct lys_module *
Michal Vasko84475152016-07-25 16:16:25 +0200397ly_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 +0200398 int implement, struct unres_schema *unres)
Michal Vasko99b0aad2015-12-01 12:28:51 +0100399{
Radek Krejcibf4e4652016-10-21 15:44:13 +0200400 const struct lys_module *mod;
Michal Vasko99b0aad2015-12-01 12:28:51 +0100401 char *module_data;
Radek Krejci03203412016-06-23 15:20:53 +0200402 int i;
Michal Vaskod3e975b2016-03-03 15:40:21 +0100403 void (*module_data_free)(void *module_data) = NULL;
Michal Vasko99b0aad2015-12-01 12:28:51 +0100404 LYS_INFORMAT format = LYS_IN_UNKNOWN;
Michal Vasko82465962015-11-10 11:03:11 +0100405
Michal Vasko84475152016-07-25 16:16:25 +0200406 if (!module) {
Radek Krejcibf4e4652016-10-21 15:44:13 +0200407 /* exception for internal modules */
Michal Vasko84475152016-07-25 16:16:25 +0200408 for (i = 0; i < INTERNAL_MODULES_COUNT; i++) {
409 if (ly_strequal(name, internal_modules[i].name, 0)) {
410 if (!revision || ly_strequal(revision, internal_modules[i].revision, 0)) {
411 /* return internal module */
412 return (struct lys_module *)ly_ctx_get_module(ctx, name, revision);
413 }
Radek Krejci03203412016-06-23 15:20:53 +0200414 }
415 }
Radek Krejcibf4e4652016-10-21 15:44:13 +0200416 if (revision) {
Radek Krejci0ec51da2016-12-14 16:42:03 +0100417 /* try to get the schema with the specific revision from the context,
418 * include the disabled modules in the search to avoid their duplication,
419 * they are enabled by the subsequent call to lys_set_implemented() */
420 for (i = INTERNAL_MODULES_COUNT, mod = NULL; i < ctx->models.used; i++) {
421 mod = ctx->models.list[i]; /* shortcut */
422 if (ly_strequal(name, mod->name, 0) && mod->rev_size && !strcmp(revision, mod->rev[0].date)) {
423 break;
424 }
425 mod = NULL;
426 }
Radek Krejcibf4e4652016-10-21 15:44:13 +0200427 if (mod) {
428 /* we get such a module, make it implemented */
429 if (lys_set_implemented(mod)) {
430 /* the schema cannot be implemented */
431 mod = NULL;
432 }
433 return mod;
434 }
435 }
436 } else {
437 /* searching for submodule, try if it is already loaded */
438 mod = (struct lys_module *)ly_ctx_get_submodule2(module, name);
439 if (mod) {
440 if (!revision || (mod->rev_size && ly_strequal(mod->rev[0].date, revision, 0))) {
441 /* success */
442 return mod;
443 } else {
444 /* there is already another revision of the submodule */
445 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, mod->rev[0].date, "revision");
446 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Multiple revisions of a submodule included.");
447 return NULL;
448 }
449 }
Radek Krejci03203412016-06-23 15:20:53 +0200450 }
451
Michal Vaskof53187d2017-01-13 13:23:14 +0100452 if (ctx->imp_clb) {
Michal Vasko84475152016-07-25 16:16:25 +0200453 if (module) {
454 mod = lys_main_module(module);
Michal Vaskof53187d2017-01-13 13:23:14 +0100455 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 +0200456 } else {
Michal Vaskof53187d2017-01-13 13:23:14 +0100457 module_data = ctx->imp_clb(name, revision, NULL, NULL, ctx->imp_clb_data, &format, &module_data_free);
Michal Vasko84475152016-07-25 16:16:25 +0200458 }
Michal Vasko99b0aad2015-12-01 12:28:51 +0100459 if (!module_data) {
Radek Krejcibf4e4652016-10-21 15:44:13 +0200460 if (module || revision) {
461 /* we already know that the specified revision is not present in context, and we have no other
462 * option in case of submodules */
463 LOGERR(LY_ESYS, "User module retrieval callback failed!");
464 return NULL;
465 } else {
466 /* get the newest revision from the context */
Radek Krejci0ec51da2016-12-14 16:42:03 +0100467 mod = ly_ctx_get_module_by(ctx, name, offsetof(struct lys_module, name), revision, 1);
468 if (mod && mod->disabled) {
469 /* enable the required module */
470 lys_set_enabled(mod);
471 }
472 return mod;
Radek Krejcibf4e4652016-10-21 15:44:13 +0200473 }
Michal Vasko82465962015-11-10 11:03:11 +0100474 }
Michal Vasko84475152016-07-25 16:16:25 +0200475
476 if (module) {
477 mod = (struct lys_module *)lys_submodule_parse(module, module_data, format, unres);
478 } else {
479 mod = (struct lys_module *)lys_parse_mem(ctx, module_data, format);
480 }
481
Michal Vasko99b0aad2015-12-01 12:28:51 +0100482 if (module_data_free) {
483 module_data_free(module_data);
Michal Vasko82465962015-11-10 11:03:11 +0100484 }
Michal Vasko99b0aad2015-12-01 12:28:51 +0100485 } else {
Michal Vasko58e5f3e2016-07-28 11:06:34 +0200486 mod = lyp_search_file(ctx, module, name, revision, implement, unres);
Michal Vasko82465962015-11-10 11:03:11 +0100487 }
488
Michal Vasko84475152016-07-25 16:16:25 +0200489 return mod;
490}
491
492API const struct lys_module *
493ly_ctx_load_module(struct ly_ctx *ctx, const char *name, const char *revision)
494{
495 if (!ctx || !name) {
496 ly_errno = LY_EINVAL;
497 return NULL;
498 }
499
Michal Vasko58e5f3e2016-07-28 11:06:34 +0200500 return ly_ctx_load_sub_module(ctx, NULL, name, revision, 1, NULL);
Michal Vasko82465962015-11-10 11:03:11 +0100501}
502
Radek Krejci85a54be2016-10-20 12:39:56 +0200503/*
504 * mods - set of removed modules, if NULL all modules are supposed to be removed so any backlink is invalid
505 */
506static int
507ctx_modules_maintain_backlinks(struct ly_ctx *ctx, struct ly_set *mods)
508{
509 int o;
510 uint8_t j;
511 unsigned int u, v;
512 struct lys_module *mod;
513 struct lys_node *elem, *next;
514 struct lys_node_leaf *leaf;
515
516 /* maintain backlinks (start with internal ietf-yang-library which have leafs as possible targets of leafrefs */
517 for (o = INTERNAL_MODULES_COUNT - 1; o < ctx->models.used; o++) {
518 mod = ctx->models.list[o]; /* shortcut */
519
520 /* 1) features */
521 for (j = 0; j < mod->features_size; j++) {
522 if (!mod->features[j].depfeatures) {
523 continue;
524 }
525 for (v = 0; v < mod->features[j].depfeatures->number; v++) {
526 if (!mods || ly_set_contains(mods, ((struct lys_feature *)mod->features[j].depfeatures->set.g[v])->module) != -1) {
527 /* depending feature is in module to remove */
528 ly_set_rm_index(mod->features[j].depfeatures, v);
529 v--;
530 }
531 }
532 if (!mod->features[j].depfeatures->number) {
533 /* all backlinks removed */
534 ly_set_free(mod->features[j].depfeatures);
535 mod->features[j].depfeatures = NULL;
536 }
537 }
538 /* identities */
539 for (u = 0; u < mod->ident_size; u++) {
540 if (!mod->ident[u].der) {
541 continue;
542 }
543 for (v = 0; v < mod->ident[u].der->number; v++) {
544 if (!mods || ly_set_contains(mods, ((struct lys_ident *)mod->ident[u].der->set.g[v])->module) != -1) {
545 /* derived identity is in module to remove */
546 ly_set_rm_index(mod->ident[u].der, v);
547 v--;
548 }
549 }
550 if (!mod->ident[u].der->number) {
551 /* all backlinks removed */
552 ly_set_free(mod->ident[u].der);
553 mod->ident[u].der = NULL;
554 }
555 }
556
557 /* leafrefs */
558 for (elem = next = mod->data; elem; elem = next) {
559 if (elem->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
560 leaf = (struct lys_node_leaf *)elem; /* shortcut */
561 if (leaf->backlinks) {
562 if (!mods) {
563 /* remove all backlinks */
564 ly_set_free(leaf->backlinks);
565 leaf->backlinks = NULL;
566 } else {
567 for (v = 0; v < leaf->backlinks->number; v++) {
568 if (ly_set_contains(mods, leaf->backlinks->set.s[v]->module) != -1) {
569 /* derived identity is in module to remove */
570 ly_set_rm_index(leaf->backlinks, v);
571 v--;
572 }
573 }
574 if (!leaf->backlinks->number) {
575 /* all backlinks removed */
576 ly_set_free(leaf->backlinks);
577 leaf->backlinks = NULL;
578 }
579 }
580 }
581 }
582
583 /* select next element to process */
584 next = elem->child;
585 /* child exception for leafs, leaflists, anyxml and groupings */
586 if (elem->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA | LYS_GROUPING)) {
587 next = NULL;
588 }
589 if (!next) {
590 /* no children, try siblings */
591 next = elem->next;
592 }
593 while (!next) {
594 /* parent is already processed, go to its sibling */
595 elem = lys_parent(elem);
596 if (!elem) {
597 /* we are done, no next element to process */
598 break;
599 }
600 /* no siblings, go back through parents */
601 next = elem->next;
602 }
603 }
604 }
605
606 return EXIT_SUCCESS;
607}
608
Radek Krejci8c107fe2016-10-17 16:00:18 +0200609API int
Radek Krejci0ec51da2016-12-14 16:42:03 +0100610lys_set_disabled(const struct lys_module *module)
611{
612 struct ly_ctx *ctx; /* shortcut */
613 struct lys_module *mod;
614 struct ly_set *mods;
615 uint8_t j, imported;
616 int i, o;
617 unsigned int u;
618
619 if (!module) {
620 ly_errno = LY_EINVAL;
621 return EXIT_FAILURE;
622 } else if (module->disabled) {
623 /* already disabled module */
624 return EXIT_SUCCESS;
625 }
626 mod = (struct lys_module *)module;
627 ctx = mod->ctx;
628
629 /* avoid disabling internal modules */
630 for (i = 0; i < INTERNAL_MODULES_COUNT; i++) {
631 if (mod == ctx->models.list[i]) {
632 LOGERR(LY_EINVAL, "Internal module \"%s\" cannot be removed.", mod->name);
633 return EXIT_FAILURE;
634 }
635 }
636
637 /* disable the module */
638 mod->disabled = 1;
639
640 /* get the complete list of modules to disable because of dependencies,
641 * we are going also to disable all the imported (not implemented) modules
642 * that are not used in any other module */
643 mods = ly_set_new();
644 ly_set_add(mods, mod, 0);
645checkdependency:
646 for (i = INTERNAL_MODULES_COUNT; i < ctx->models.used; i++) {
647 mod = ctx->models.list[i]; /* shortcut */
648 if (mod->disabled) {
649 /* skip the already disabled modules */
650 continue;
651 }
652
653 /* check depndency of imported modules */
654 for (j = 0; j < mod->imp_size; j++) {
655 for (u = 0; u < mods->number; u++) {
656 if (mod->imp[j].module == mods->set.g[u]) {
657 /* module is importing some module to disable, so it must be also disabled */
658 mod->disabled = 1;
659 ly_set_add(mods, mod, 0);
660 /* we have to start again because some of the already checked modules can
661 * depend on the one we have just decided to disable */
662 goto checkdependency;
663 }
664 }
665 }
666 /* check if the imported module is used in any module supposed to be kept */
667 if (!mod->implemented) {
668 imported = 0;
669 for (o = INTERNAL_MODULES_COUNT; o < ctx->models.used; o++) {
670 if (ctx->models.list[o]->disabled) {
671 /* skip modules already disabled */
672 continue;
673 }
674 for (j = 0; j < ctx->models.list[o]->imp_size; j++) {
675 if (ctx->models.list[o]->imp[j].module == mod) {
676 /* the module is used in some other module not yet selected to be disabled */
677 imported = 1;
678 goto imported;
679 }
680 }
681 }
682imported:
683 if (!imported) {
684 /* module is not implemented and neither imported by any other module in context
685 * which is supposed to be kept enabled after this operation, so we are going to disable also
686 * this module */
687 mod->disabled = 1;
688 ly_set_add(mods, mod, 0);
689 /* we have to start again, this time not because other module can depend on this one
690 * (we know that there is no such module), but because the module can import module
691 * that could became useless. If there are no imports, we can continue */
692 if (mod->imp_size) {
693 goto checkdependency;
694 }
695 }
696 }
697 }
698
699 /* before removing applied deviations, augments and updating leafrefs, we have to enable the modules
700 * to disable to allow all that operations */
701 for (u = 0; u < mods->number; u++) {
702 ((struct lys_module *)mods->set.g[u])->disabled = 0;
703 }
704
705 /* maintain backlinks (start with internal ietf-yang-library which have leafs as possible targets of leafrefs */
706 ctx_modules_maintain_backlinks(ctx, mods);
707
708 /* remove the applied deviations and augments */
709 for (u = 0; u < mods->number; u++) {
710 lys_sub_module_remove_devs_augs((struct lys_module *)mods->set.g[u]);
711 }
712
713 /* now again disable the modules to disable */
714 for (u = 0; u < mods->number; u++) {
715 ((struct lys_module *)mods->set.g[u])->disabled = 1;
716 }
717
718 /* free the set */
719 ly_set_free(mods);
720
721 /* update the module-set-id */
722 ctx->models.module_set_id++;
723
724 return EXIT_SUCCESS;
725}
726
727static void
728lys_set_enabled_(struct ly_set *mods, struct lys_module *mod)
729{
730 unsigned int i;
731
732 ly_set_add(mods, mod, 0);
733 mod->disabled = 0;
734
735 /* go recursively */
736 for (i = 0; i < mod->imp_size; i++) {
737 if (!mod->imp[i].module->disabled) {
738 continue;
739 }
740
741 lys_set_enabled_(mods, mod->imp[i].module);
742 }
743}
744
745API int
746lys_set_enabled(const struct lys_module *module)
747{
748 struct ly_ctx *ctx; /* shortcut */
749 struct lys_module *mod;
750 struct ly_set *mods, *disabled;
751 int i;
752 unsigned int u, v;
753
754 if (!module) {
755 ly_errno = LY_EINVAL;
756 return EXIT_FAILURE;
757 } else if (!module->disabled) {
758 /* already enabled module */
759 return EXIT_SUCCESS;
760 }
761 mod = (struct lys_module *)module;
762 ctx = mod->ctx;
763
764 /* avoid disabling internal modules */
765 for (i = 0; i < INTERNAL_MODULES_COUNT; i++) {
766 if (mod == ctx->models.list[i]) {
767 LOGERR(LY_EINVAL, "Internal module \"%s\" cannot be removed.", mod->name);
768 return EXIT_FAILURE;
769 }
770 }
771
772 mods = ly_set_new();
773 disabled = ly_set_new();
774
775 /* enable the module, including its dependencies */
776 lys_set_enabled_(mods, mod);
777
778 /* we will go through the all disabled modules in the context, if the module has no dependency (import)
779 * that is still disabled AND at least one of its imported module is from the set we are enabling now,
780 * it is going to be also enabled. This way we try to revert everething that was possibly done by
781 * lys_set_disabled(). */
782checkdependency:
783 for (i = INTERNAL_MODULES_COUNT; i < ctx->models.used; i++) {
784 mod = ctx->models.list[i]; /* shortcut */
785 if (!mod->disabled || ly_set_contains(disabled, mod) != -1) {
786 /* skip the enabled modules */
787 continue;
788 }
789
790 /* check imported modules */
791 for (u = 0; u < mod->imp_size; u++) {
792 if (mod->imp[u].module->disabled) {
793 /* it has disabled dependency so it must stay disabled */
794 break;
795 }
796 }
797 if (u < mod->imp_size) {
798 /* it has disabled dependency, continue with the next module in the context */
799 continue;
800 }
801
802 /* get know if at least one of the imported modules is being enabled this time */
803 for (u = 0; u < mod->imp_size; u++) {
804 for (v = 0; v < mods->number; v++) {
805 if (mod->imp[u].module == mods->set.g[v]) {
806 /* yes, it is, so they are connected and we are going to enable it as well,
807 * it is not necessary to call recursive lys_set_enable_() because we already
808 * know that there is no disabled import to enable */
809 mod->disabled = 0;
810 ly_set_add(mods, mod, 0);
811 /* we have to start again because some of the already checked modules can
812 * depend on the one we have just decided to enable */
813 goto checkdependency;
814 }
815 }
816 }
817
818 /* this module is disabled, but it does not depend on any other disabled module and none
819 * of its imports was not enabled in this call. No future enabling of the disabled module
820 * will change this so we can remember the module and skip it next time we will have to go
821 * through the all context because of the checkdependency goto.
822 */
823 ly_set_add(disabled, mod, 0);
824 }
825
826 /* maintain backlinks (start with internal ietf-yang-library which have leafs as possible targets of leafrefs */
827 ctx_modules_maintain_backlinks(ctx, mods);
828
829 /* re-apply the deviations and augments */
830 for (v = 0; v < mods->number; v++) {
831 lys_sub_module_apply_devs_augs((struct lys_module *)mods->set.g[v]);
832 }
833
834 /* free the sets */
835 ly_set_free(mods);
836 ly_set_free(disabled);
837
838 /* update the module-set-id */
839 ctx->models.module_set_id++;
840
841 return EXIT_SUCCESS;
842}
843
844API int
845ly_ctx_remove_module(const struct lys_module *module,
Radek Krejci8c107fe2016-10-17 16:00:18 +0200846 void (*private_destructor)(const struct lys_node *node, void *priv))
847{
Radek Krejci0ec51da2016-12-14 16:42:03 +0100848 struct ly_ctx *ctx; /* shortcut */
Radek Krejci8c107fe2016-10-17 16:00:18 +0200849 struct lys_module *mod = NULL;
850 struct ly_set *mods;
851 uint8_t j, imported;
852 int i, o;
853 unsigned int u;
854
Radek Krejci0ec51da2016-12-14 16:42:03 +0100855 if (!module) {
Radek Krejci8c107fe2016-10-17 16:00:18 +0200856 ly_errno = LY_EINVAL;
857 return EXIT_FAILURE;
858 }
859
Radek Krejci0ec51da2016-12-14 16:42:03 +0100860 mod = (struct lys_module *)module;
861 ctx = mod->ctx;
862
Radek Krejci8c107fe2016-10-17 16:00:18 +0200863 /* avoid removing internal modules ... */
864 for (i = 0; i < INTERNAL_MODULES_COUNT; i++) {
865 if (mod == ctx->models.list[i]) {
Radek Krejci0ec51da2016-12-14 16:42:03 +0100866 LOGERR(LY_EINVAL, "Internal module \"%s\" cannot be removed.", mod->name);
Radek Krejci8c107fe2016-10-17 16:00:18 +0200867 return EXIT_FAILURE;
868 }
869 }
870 /* ... and hide the module from the further processing of the context modules list */
871 for (i = INTERNAL_MODULES_COUNT; i < ctx->models.used; i++) {
872 if (mod == ctx->models.list[i]) {
873 ctx->models.list[i] = NULL;
874 break;
875 }
876 }
877
878 /* get the complete list of modules to remove because of dependencies,
879 * we are going also to remove all the imported (not implemented) modules
880 * that are not used in any other module */
881 mods = ly_set_new();
882 ly_set_add(mods, mod, 0);
883checkdependency:
884 for (i = INTERNAL_MODULES_COUNT; i < ctx->models.used; i++) {
885 mod = ctx->models.list[i]; /* shortcut */
886 if (!mod) {
887 /* skip modules already selected for removing */
888 continue;
889 }
890
891 /* check depndency of imported modules */
892 for (j = 0; j < mod->imp_size; j++) {
893 for (u = 0; u < mods->number; u++) {
894 if (mod->imp[j].module == mods->set.g[u]) {
895 /* module is importing some module to remove, so it must be also removed */
896 ly_set_add(mods, mod, 0);
897 ctx->models.list[i] = NULL;
898 /* we have to start again because some of the already checked modules can
899 * depend on the one we have just decided to remove */
900 goto checkdependency;
901 }
902 }
903 }
904 /* check if the imported module is used in any module supposed to be kept */
905 if (!mod->implemented) {
906 imported = 0;
907 for (o = INTERNAL_MODULES_COUNT; o < ctx->models.used; o++) {
908 if (!ctx->models.list[o]) {
909 /* skip modules already selected for removing */
910 continue;
911 }
912 for (j = 0; j < ctx->models.list[o]->imp_size; j++) {
913 if (ctx->models.list[o]->imp[j].module == mod) {
914 /* the module is used in some other module not yet selected to be deleted */
915 imported = 1;
916 goto imported;
917 }
918 }
919 }
920imported:
921 if (!imported) {
922 /* module is not implemented and neither imported by any other module in context
923 * which is supposed to be kept after this operation, so we are going to remove also
924 * this useless module */
925 ly_set_add(mods, mod, 0);
926 ctx->models.list[i] = NULL;
927 /* we have to start again, this time not because other module can depend on this one
Radek Krejci0ec51da2016-12-14 16:42:03 +0100928 * (we know that there is no such module), but because the module can import module
Radek Krejci8c107fe2016-10-17 16:00:18 +0200929 * that could became useless. If there are no imports, we can continue */
930 if (mod->imp_size) {
931 goto checkdependency;
932 }
933 }
934 }
935 }
936
Radek Krejci8c107fe2016-10-17 16:00:18 +0200937
938 /* consolidate the modules list */
939 for (i = o = INTERNAL_MODULES_COUNT; i < ctx->models.used; i++) {
940 if (ctx->models.list[o]) {
941 /* used cell */
942 o++;
943 } else {
944 /* the current output cell is empty, move here an input cell */
945 ctx->models.list[o] = ctx->models.list[i];
946 ctx->models.list[i] = NULL;
947 }
948 }
949 /* get the last used cell to get know the number of used */
950 while (!ctx->models.list[o]) {
951 o--;
952 }
953 ctx->models.used = o + 1;
954 ctx->models.module_set_id++;
955
Radek Krejci85a54be2016-10-20 12:39:56 +0200956 /* maintain backlinks (start with internal ietf-yang-library which have leafs as possible targets of leafrefs */
957 ctx_modules_maintain_backlinks(ctx, mods);
958
959 /* free the modules */
960 for (u = 0; u < mods->number; u++) {
Radek Krejcib2541a32016-12-12 16:45:57 +0100961 /* remove the applied deviations and augments */
962 lys_sub_module_remove_devs_augs((struct lys_module *)mods->set.g[u]);
Radek Krejci85a54be2016-10-20 12:39:56 +0200963 /* remove the module */
964 lys_free((struct lys_module *)mods->set.g[u], private_destructor, 0);
965 }
966 ly_set_free(mods);
967
Radek Krejci8c107fe2016-10-17 16:00:18 +0200968 return EXIT_SUCCESS;
969}
970
Radek Krejci85a54be2016-10-20 12:39:56 +0200971API void
972ly_ctx_clean(struct ly_ctx *ctx, void (*private_destructor)(const struct lys_node *node, void *priv))
973{
974 int i;
975
976 if (!ctx) {
977 return;
978 }
979
980 /* models list */
981 for (i = INTERNAL_MODULES_COUNT; i < ctx->models.used; ++i) {
982 lys_free(ctx->models.list[i], private_destructor, 0);
983 ctx->models.list[i] = NULL;
984 }
985 ctx->models.used = INTERNAL_MODULES_COUNT;
986 ctx->models.module_set_id++;
987
988 /* maintain backlinks (actually done only with ietf-yang-library since its leafs cna be target of leafref) */
989 ctx_modules_maintain_backlinks(ctx, NULL);
990}
991
Michal Vaskod7957c02016-04-01 10:27:26 +0200992API const struct lys_module *
993ly_ctx_get_module_iter(const struct ly_ctx *ctx, uint32_t *idx)
994{
995 if (!ctx || !idx) {
996 ly_errno = LY_EINVAL;
997 return NULL;
998 }
999
Radek Krejci0ec51da2016-12-14 16:42:03 +01001000 for ( ; *idx < (unsigned)ctx->models.used; (*idx)++) {
1001 if (!ctx->models.list[(*idx)]->disabled) {
1002 return ctx->models.list[(*idx)++];
1003 }
1004 }
1005
1006 return NULL;
1007}
1008
1009API const struct lys_module *
1010ly_ctx_get_disabled_module_iter(const struct ly_ctx *ctx, uint32_t *idx)
1011{
1012 if (!ctx || !idx) {
1013 ly_errno = LY_EINVAL;
Michal Vaskod7957c02016-04-01 10:27:26 +02001014 return NULL;
1015 }
1016
Radek Krejci0ec51da2016-12-14 16:42:03 +01001017 for ( ; *idx < (unsigned)ctx->models.used; (*idx)++) {
1018 if (ctx->models.list[(*idx)]->disabled) {
1019 return ctx->models.list[(*idx)++];
1020 }
1021 }
1022
1023 return NULL;
Michal Vaskod7957c02016-04-01 10:27:26 +02001024}
1025
Michal Vasko209a6222015-10-16 09:51:07 +02001026static int
1027ylib_feature(struct lyd_node *parent, struct lys_module *cur_mod)
1028{
1029 int i, j;
1030
1031 /* module features */
1032 for (i = 0; i < cur_mod->features_size; ++i) {
1033 if (!(cur_mod->features[i].flags & LYS_FENABLED)) {
1034 continue;
1035 }
1036
Michal Vasko3e671b52015-10-23 16:23:15 +02001037 if (!lyd_new_leaf(parent, NULL, "feature", cur_mod->features[i].name)) {
Michal Vasko209a6222015-10-16 09:51:07 +02001038 return EXIT_FAILURE;
1039 }
1040 }
1041
1042 /* submodule features */
Radek Krejcic071c542016-01-27 14:57:51 +01001043 for (i = 0; i < cur_mod->inc_size && cur_mod->inc[i].submodule; ++i) {
Michal Vasko209a6222015-10-16 09:51:07 +02001044 for (j = 0; j < cur_mod->inc[i].submodule->features_size; ++j) {
1045 if (!(cur_mod->inc[i].submodule->features[j].flags & LYS_FENABLED)) {
1046 continue;
1047 }
1048
Michal Vasko3e671b52015-10-23 16:23:15 +02001049 if (!lyd_new_leaf(parent, NULL, "feature", cur_mod->inc[i].submodule->features[j].name)) {
Michal Vasko209a6222015-10-16 09:51:07 +02001050 return EXIT_FAILURE;
1051 }
1052 }
1053 }
1054
1055 return EXIT_SUCCESS;
1056}
1057
1058static int
Michal Vaskoff006c12016-02-17 11:15:19 +01001059ylib_deviation(struct lyd_node *parent, struct lys_module *cur_mod)
Michal Vasko97d8c6d2016-02-12 11:05:48 +01001060{
Michal Vasko89563fc2016-07-28 16:19:35 +02001061 uint32_t i = 0, j;
1062 const struct lys_module *mod;
Michal Vasko209a6222015-10-16 09:51:07 +02001063 struct lyd_node *cont;
Michal Vasko89563fc2016-07-28 16:19:35 +02001064 const char *ptr;
Michal Vasko209a6222015-10-16 09:51:07 +02001065
Michal Vasko89563fc2016-07-28 16:19:35 +02001066 if (cur_mod->deviated) {
1067 while ((mod = ly_ctx_get_module_iter(cur_mod->ctx, &i))) {
1068 if (mod == cur_mod) {
1069 continue;
Michal Vasko209a6222015-10-16 09:51:07 +02001070 }
Michal Vasko209a6222015-10-16 09:51:07 +02001071
Michal Vasko89563fc2016-07-28 16:19:35 +02001072 for (j = 0; j < mod->deviation_size; ++j) {
1073 ptr = strstr(mod->deviation[j].target_name, cur_mod->name);
1074 if (ptr && ptr[strlen(cur_mod->name)] == ':') {
1075 cont = lyd_new(parent, NULL, "deviation");
1076 if (!cont) {
1077 return EXIT_FAILURE;
1078 }
1079
1080 if (!lyd_new_leaf(cont, NULL, "name", mod->name)) {
1081 return EXIT_FAILURE;
1082 }
1083 if (!lyd_new_leaf(cont, NULL, "revision", (mod->rev_size ? mod->rev[0].date : ""))) {
1084 return EXIT_FAILURE;
1085 }
Michal Vasko0c2215b2016-08-25 14:18:43 +02001086
1087 break;
Michal Vasko89563fc2016-07-28 16:19:35 +02001088 }
Michal Vasko209a6222015-10-16 09:51:07 +02001089 }
1090 }
1091 }
1092
1093 return EXIT_SUCCESS;
1094}
1095
1096static int
1097ylib_submodules(struct lyd_node *parent, struct lys_module *cur_mod)
1098{
1099 int i;
Radek Krejcia77904e2016-02-25 16:23:45 +01001100 char *str;
Radek Krejcid9723912016-09-16 17:06:06 +02001101 struct lyd_node *item;
Michal Vasko209a6222015-10-16 09:51:07 +02001102
Radek Krejcic071c542016-01-27 14:57:51 +01001103 for (i = 0; i < cur_mod->inc_size && cur_mod->inc[i].submodule; ++i) {
Radek Krejcid9723912016-09-16 17:06:06 +02001104 item = lyd_new(parent, NULL, "submodule");
Radek Krejci6e05cea2015-12-10 16:34:37 +01001105 if (!item) {
Michal Vasko209a6222015-10-16 09:51:07 +02001106 return EXIT_FAILURE;
1107 }
1108
Radek Krejci6e05cea2015-12-10 16:34:37 +01001109 if (!lyd_new_leaf(item, NULL, "name", cur_mod->inc[i].submodule->name)) {
Michal Vasko209a6222015-10-16 09:51:07 +02001110 return EXIT_FAILURE;
1111 }
Radek Krejci6e05cea2015-12-10 16:34:37 +01001112 if (!lyd_new_leaf(item, NULL, "revision", (cur_mod->inc[i].submodule->rev_size ?
Michal Vasko3e671b52015-10-23 16:23:15 +02001113 cur_mod->inc[i].submodule->rev[0].date : ""))) {
Michal Vasko209a6222015-10-16 09:51:07 +02001114 return EXIT_FAILURE;
1115 }
Radek Krejcia77904e2016-02-25 16:23:45 +01001116 if (cur_mod->inc[i].submodule->filepath) {
Radek Krejci95aa2012016-03-03 11:21:09 +01001117 if (asprintf(&str, "file://%s", cur_mod->inc[i].submodule->filepath) == -1) {
Radek Krejcia77904e2016-02-25 16:23:45 +01001118 LOGMEM;
1119 return EXIT_FAILURE;
Radek Krejci6e65af92016-03-07 12:48:19 +01001120 } else if (!lyd_new_leaf(item, NULL, "schema", str)) {
Radek Krejci19f9ede2016-02-25 16:29:21 +01001121 free(str);
Radek Krejcia77904e2016-02-25 16:23:45 +01001122 return EXIT_FAILURE;
1123 }
Radek Krejci19f9ede2016-02-25 16:29:21 +01001124 free(str);
Michal Vasko209a6222015-10-16 09:51:07 +02001125 }
1126 }
1127
1128 return EXIT_SUCCESS;
1129}
1130
1131API struct lyd_node *
1132ly_ctx_info(struct ly_ctx *ctx)
1133{
1134 int i;
1135 char id[8];
Radek Krejcia77904e2016-02-25 16:23:45 +01001136 char *str;
Michal Vasko1e62a092015-12-01 12:27:20 +01001137 const struct lys_module *mod;
Michal Vasko209a6222015-10-16 09:51:07 +02001138 struct lyd_node *root, *cont;
1139
Michal Vasko7eccc6c2016-03-24 14:56:33 +01001140 if (!ctx) {
1141 ly_errno = LY_EINVAL;
1142 return NULL;
1143 }
1144
Radek Krejcibd9e8d22016-02-03 14:11:48 +01001145 mod = ly_ctx_get_module(ctx, "ietf-yang-library", IETF_YANG_LIB_REV);
1146 if (!mod || !mod->data) {
1147 LOGINT;
Michal Vasko209a6222015-10-16 09:51:07 +02001148 return NULL;
1149 }
1150
Radek Krejcibd9e8d22016-02-03 14:11:48 +01001151 root = lyd_new(NULL, mod, "modules-state");
Michal Vasko209a6222015-10-16 09:51:07 +02001152 if (!root) {
1153 return NULL;
1154 }
1155
1156 for (i = 0; i < ctx->models.used; ++i) {
Radek Krejci0ec51da2016-12-14 16:42:03 +01001157 if (ctx->models.list[i]->disabled) {
1158 /* skip the disabled modules */
1159 continue;
1160 }
1161
Michal Vasko209a6222015-10-16 09:51:07 +02001162 cont = lyd_new(root, NULL, "module");
1163 if (!cont) {
1164 lyd_free(root);
1165 return NULL;
1166 }
1167
Michal Vasko3e671b52015-10-23 16:23:15 +02001168 if (!lyd_new_leaf(cont, NULL, "name", ctx->models.list[i]->name)) {
Michal Vasko209a6222015-10-16 09:51:07 +02001169 lyd_free(root);
1170 return NULL;
1171 }
Michal Vasko3e671b52015-10-23 16:23:15 +02001172 if (!lyd_new_leaf(cont, NULL, "revision", (ctx->models.list[i]->rev_size ?
Michal Vasko209a6222015-10-16 09:51:07 +02001173 ctx->models.list[i]->rev[0].date : ""))) {
1174 lyd_free(root);
1175 return NULL;
1176 }
Radek Krejcia77904e2016-02-25 16:23:45 +01001177 if (ctx->models.list[i]->filepath) {
Radek Krejci15412ca2016-03-03 11:16:52 +01001178 if (asprintf(&str, "file://%s", ctx->models.list[i]->filepath) == -1) {
Radek Krejcia77904e2016-02-25 16:23:45 +01001179 LOGMEM;
1180 lyd_free(root);
1181 return NULL;
1182 } else if (!lyd_new_leaf(cont, NULL, "schema", str)) {
Radek Krejci19f9ede2016-02-25 16:29:21 +01001183 free(str);
Radek Krejcia77904e2016-02-25 16:23:45 +01001184 lyd_free(root);
1185 return NULL;
1186 }
Radek Krejci19f9ede2016-02-25 16:29:21 +01001187 free(str);
Michal Vasko209a6222015-10-16 09:51:07 +02001188 }
Michal Vasko3e671b52015-10-23 16:23:15 +02001189 if (!lyd_new_leaf(cont, NULL, "namespace", ctx->models.list[i]->ns)) {
Michal Vasko209a6222015-10-16 09:51:07 +02001190 lyd_free(root);
1191 return NULL;
1192 }
1193 if (ylib_feature(cont, ctx->models.list[i])) {
1194 lyd_free(root);
1195 return NULL;
1196 }
Michal Vaskoff006c12016-02-17 11:15:19 +01001197 if (ylib_deviation(cont, ctx->models.list[i])) {
Michal Vasko209a6222015-10-16 09:51:07 +02001198 lyd_free(root);
1199 return NULL;
1200 }
1201 if (ctx->models.list[i]->implemented
Radek Krejcibd9e8d22016-02-03 14:11:48 +01001202 && !lyd_new_leaf(cont, NULL, "conformance-type", "implement")) {
Michal Vasko209a6222015-10-16 09:51:07 +02001203 lyd_free(root);
1204 return NULL;
1205 }
1206 if (!ctx->models.list[i]->implemented
Radek Krejcibd9e8d22016-02-03 14:11:48 +01001207 && !lyd_new_leaf(cont, NULL, "conformance-type", "import")) {
Michal Vasko209a6222015-10-16 09:51:07 +02001208 lyd_free(root);
1209 return NULL;
1210 }
1211 if (ylib_submodules(cont, ctx->models.list[i])) {
1212 lyd_free(root);
1213 return NULL;
1214 }
1215 }
1216
1217 sprintf(id, "%u", ctx->models.module_set_id);
Michal Vasko3e671b52015-10-23 16:23:15 +02001218 if (!lyd_new_leaf(root, mod, "module-set-id", id)) {
Michal Vasko209a6222015-10-16 09:51:07 +02001219 lyd_free(root);
1220 return NULL;
1221 }
1222
Michal Vaskocdb90172016-09-13 09:34:36 +02001223 if (lyd_validate(&root, LYD_OPT_NOSIBLINGS, NULL)) {
Michal Vasko209a6222015-10-16 09:51:07 +02001224 lyd_free(root);
1225 return NULL;
1226 }
1227
1228 return root;
1229}
Michal Vasko3edeaf72016-02-11 13:17:43 +01001230
1231API const struct lys_node *
Michal Vasko3547c532016-03-14 09:40:50 +01001232ly_ctx_get_node(struct ly_ctx *ctx, const struct lys_node *start, const char *nodeid)
Michal Vasko3edeaf72016-02-11 13:17:43 +01001233{
Michal Vaskoe733d682016-03-14 09:08:27 +01001234 const struct lys_node *node;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001235
Michal Vasko3547c532016-03-14 09:40:50 +01001236 if (!ctx || !nodeid || ((nodeid[0] != '/') && !start)) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001237 ly_errno = LY_EINVAL;
1238 return NULL;
1239 }
1240
Michal Vaskoe733d682016-03-14 09:08:27 +01001241 /* sets error and everything */
Michal Vasko8d26e5c2016-09-08 10:03:49 +02001242 node = resolve_json_nodeid(nodeid, ctx, start);
Michal Vasko3edeaf72016-02-11 13:17:43 +01001243
Michal Vaskoe733d682016-03-14 09:08:27 +01001244 return node;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001245}