blob: c04d84951c72611325ad1b69855636b633ebffe2 [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 Krejcibd9e8d22016-02-03 14:11:48 +010034#define IETF_YANG_LIB_PATH "../models/ietf-yang-library@2016-02-01.h"
35#define IETF_YANG_LIB_REV "2016-02-01"
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},
53 {"ietf-yang-library", "2016-02-01", (const char*)ietf_yang_library_2016_02_01_yin, 1, LYS_IN_YIN}
54};
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{
147 return ctx->models.search_path;
148}
149
Michal Vasko60ba9a62015-07-03 14:42:31 +0200150API void
Radek Krejcifa0b5e02016-02-04 13:57:03 +0100151ly_ctx_destroy(struct ly_ctx *ctx, void (*private_destructor)(const struct lys_node *node, void *priv))
Radek Krejcida04f4a2015-05-21 12:54:09 +0200152{
Michal Vasko627975a2016-02-11 11:39:03 +0100153 int i;
154
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200155 if (!ctx) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200156 return;
157 }
Radek Krejcida04f4a2015-05-21 12:54:09 +0200158
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200159 /* models list */
Michal Vasko627975a2016-02-11 11:39:03 +0100160 for (i = 0; i < ctx->models.used; ++i) {
161 lys_free(ctx->models.list[i], private_destructor, 0);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200162 }
163 free(ctx->models.search_path);
164 free(ctx->models.list);
Radek Krejcida04f4a2015-05-21 12:54:09 +0200165
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200166 /* dictionary */
167 lydict_clean(&ctx->dict);
Radek Krejcida04f4a2015-05-21 12:54:09 +0200168
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200169 free(ctx);
Radek Krejcida04f4a2015-05-21 12:54:09 +0200170}
171
Michal Vasko1e62a092015-12-01 12:27:20 +0100172API const struct lys_submodule *
Radek Krejci62f0da72016-03-07 11:35:43 +0100173ly_ctx_get_submodule2(const struct lys_module *main_module, const char *submodule)
174{
175 struct lys_submodule *result;
176 int i;
177
178 if (!main_module || !submodule) {
179 ly_errno = LY_EINVAL;
180 return NULL;
181 }
182
183 /* search in submodules list */
184 for (i = 0; i < main_module->inc_size; i++) {
185 result = main_module->inc[i].submodule;
186 if (result && ly_strequal(submodule, result->name, 0)) {
187 return result;
188 }
189 }
190
191 return NULL;
192}
193
194API const struct lys_submodule *
Michal Vaskof6d94c62016-04-05 11:21:54 +0200195ly_ctx_get_submodule(const struct ly_ctx *ctx, const char *module, const char *revision, const char *submodule,
196 const char *sub_revision)
Radek Krejciefaeba32015-05-27 14:30:57 +0200197{
Radek Krejcie7973552016-03-07 08:12:01 +0100198 const struct lys_module *mainmod;
Michal Vaskof6d94c62016-04-05 11:21:54 +0200199 const struct lys_submodule *ret = NULL, *submod;
200 uint32_t idx = 0;
Radek Krejciefaeba32015-05-27 14:30:57 +0200201
Michal Vaskof6d94c62016-04-05 11:21:54 +0200202 if (!ctx || !submodule || (revision && !module)) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200203 ly_errno = LY_EINVAL;
204 return NULL;
205 }
Radek Krejciefaeba32015-05-27 14:30:57 +0200206
Michal Vaskof6d94c62016-04-05 11:21:54 +0200207 while ((mainmod = ly_ctx_get_module_iter(ctx, &idx))) {
208 if (module && strcmp(mainmod->name, module)) {
209 /* main module name does not match */
210 continue;
211 }
212
213 if (revision && (!mainmod->rev || strcmp(revision, mainmod->rev[0].date))) {
214 /* main module revision does not match */
215 continue;
216 }
217
218 submod = ly_ctx_get_submodule2(mainmod, submodule);
219 if (!submod) {
220 continue;
221 }
222
223 if (!sub_revision) {
224 /* store only if newer */
225 if (ret) {
226 if (submod->rev && (!ret->rev || (strcmp(submod->rev[0].date, ret->rev[0].date) > 0))) {
227 ret = submod;
228 }
229 } else {
230 ret = submod;
231 }
232 } else {
233 /* store only if revision matches, we are done if it does */
234 if (!submod->rev) {
235 continue;
236 } else if (!strcmp(sub_revision, submod->rev[0].date)) {
237 ret = submod;
238 break;
239 }
240 }
Radek Krejcia7533f22016-03-07 07:37:45 +0100241 }
Radek Krejcic071c542016-01-27 14:57:51 +0100242
Michal Vaskof6d94c62016-04-05 11:21:54 +0200243 return ret;
Radek Krejciefaeba32015-05-27 14:30:57 +0200244}
245
Michal Vasko1e62a092015-12-01 12:27:20 +0100246static const struct lys_module *
247ly_ctx_get_module_by(const struct ly_ctx *ctx, const char *key, int offset, const char *revision)
Radek Krejciefaeba32015-05-27 14:30:57 +0200248{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200249 int i;
Radek Krejcib8048692015-08-05 13:36:34 +0200250 struct lys_module *result = NULL;
Radek Krejciefaeba32015-05-27 14:30:57 +0200251
Radek Krejcifd4e6e32015-08-10 15:00:51 +0200252 if (!ctx || !key) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200253 ly_errno = LY_EINVAL;
254 return NULL;
255 }
Radek Krejciefaeba32015-05-27 14:30:57 +0200256
Radek Krejcidce51452015-06-16 15:20:08 +0200257 for (i = 0; i < ctx->models.used; i++) {
Radek Krejcifd4e6e32015-08-10 15:00:51 +0200258 /* use offset to get address of the pointer to string (char**), remember that offset is in
259 * bytes, so we have to cast the pointer to the module to (char*), finally, we want to have
260 * string not the pointer to string
261 */
262 if (!ctx->models.list[i] || strcmp(key, *(char**)(((char*)ctx->models.list[i]) + offset))) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200263 continue;
264 }
Radek Krejciefaeba32015-05-27 14:30:57 +0200265
Radek Krejcif647e612015-07-30 11:36:07 +0200266 if (!revision) {
267 /* compare revisons and remember the newest one */
268 if (result) {
269 if (!ctx->models.list[i]->rev_size) {
270 /* the current have no revision, keep the previous with some revision */
271 continue;
272 }
273 if (result->rev_size && strcmp(ctx->models.list[i]->rev[0].date, result->rev[0].date) < 0) {
274 /* the previous found matching module has a newer revision */
275 continue;
276 }
277 }
278
279 /* remember the current match and search for newer version */
280 result = ctx->models.list[i];
281 } else {
282 if (ctx->models.list[i]->rev_size && !strcmp(revision, ctx->models.list[i]->rev[0].date)) {
283 /* matching revision */
Michal Vasko97586502015-08-12 14:32:18 +0200284 result = ctx->models.list[i];
285 break;
Radek Krejcif647e612015-07-30 11:36:07 +0200286 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200287 }
288 }
Radek Krejciefaeba32015-05-27 14:30:57 +0200289
Radek Krejcif647e612015-07-30 11:36:07 +0200290 return result;
Radek Krejcifd4e6e32015-08-10 15:00:51 +0200291
292}
293
Michal Vasko1e62a092015-12-01 12:27:20 +0100294API const struct lys_module *
295ly_ctx_get_module_by_ns(const struct ly_ctx *ctx, const char *ns, const char *revision)
Radek Krejcifd4e6e32015-08-10 15:00:51 +0200296{
297 return ly_ctx_get_module_by(ctx, ns, offsetof(struct lys_module, ns), revision);
298}
299
Michal Vasko1e62a092015-12-01 12:27:20 +0100300API const struct lys_module *
301ly_ctx_get_module(const struct ly_ctx *ctx, const char *name, const char *revision)
Radek Krejcifd4e6e32015-08-10 15:00:51 +0200302{
303 return ly_ctx_get_module_by(ctx, name, offsetof(struct lys_module, name), revision);
Radek Krejcida04f4a2015-05-21 12:54:09 +0200304}
Michal Vasko3ec07dc2015-06-30 15:51:30 +0200305
Radek Krejci21601a32016-03-07 11:39:27 +0100306API const struct lys_module *
307ly_ctx_get_module_older(const struct ly_ctx *ctx, const struct lys_module *module)
308{
309 int i;
310 const struct lys_module *result = NULL, *iter;
311
312 if (!ctx || !module || !module->rev_size) {
313 ly_errno = LY_EINVAL;
314 return NULL;
315 }
316
317
318 for (i = 0; i < ctx->models.used; i++) {
319 iter = ctx->models.list[i];
320 if (iter == module || !iter->rev_size) {
321 /* iter is the module itself or iter has no revision */
322 continue;
323 }
324 if (!ly_strequal(module->name, iter->name, 0)) {
325 /* different module */
326 continue;
327 }
328 if (strcmp(iter->rev[0].date, module->rev[0].date) < 0) {
329 /* iter is older than module */
330 if (result) {
331 if (strcmp(iter->rev[0].date, result->rev[0].date) > 0) {
332 /* iter is newer than current result */
333 result = iter;
334 }
335 } else {
336 result = iter;
337 }
338 }
339 }
340
341 return result;
342}
343
Michal Vasko99b0aad2015-12-01 12:28:51 +0100344API void
345ly_ctx_set_module_clb(struct ly_ctx *ctx, ly_module_clb clb, void *user_data)
Michal Vasko82465962015-11-10 11:03:11 +0100346{
Michal Vasko99b0aad2015-12-01 12:28:51 +0100347 ctx->module_clb = clb;
348 ctx->module_clb_data = user_data;
349}
350
351API ly_module_clb
352ly_ctx_get_module_clb(const struct ly_ctx *ctx, void **user_data)
353{
354 if (user_data) {
355 *user_data = ctx->module_clb_data;
356 }
357 return ctx->module_clb;
358}
359
360API const struct lys_module *
361ly_ctx_load_module(struct ly_ctx *ctx, const char *name, const char *revision)
362{
Michal Vasko5a721fd2016-02-16 12:16:48 +0100363 const struct lys_module *module;
Michal Vasko99b0aad2015-12-01 12:28:51 +0100364 char *module_data;
Radek Krejci03203412016-06-23 15:20:53 +0200365 int i;
Michal Vaskod3e975b2016-03-03 15:40:21 +0100366 void (*module_data_free)(void *module_data) = NULL;
Michal Vasko99b0aad2015-12-01 12:28:51 +0100367 LYS_INFORMAT format = LYS_IN_UNKNOWN;
Michal Vasko82465962015-11-10 11:03:11 +0100368
369 if (!ctx || !name) {
370 ly_errno = LY_EINVAL;
371 return NULL;
372 }
373
Radek Krejci03203412016-06-23 15:20:53 +0200374 /* exception for internal modules */
375 for (i = 0; i < INTERNAL_MODULES_COUNT; i++) {
376 if (ly_strequal(name, internal_modules[i].name, 0)) {
377 if (!revision || ly_strequal(revision, internal_modules[i].revision, 0)) {
378 /* return internal module */
379 return ly_ctx_get_module(ctx, name, revision);
380 }
381 }
382 }
383
Michal Vasko99b0aad2015-12-01 12:28:51 +0100384 if (ctx->module_clb) {
385 module_data = ctx->module_clb(name, revision, ctx->module_clb_data, &format, &module_data_free);
386 if (!module_data) {
Radek Krejci0fd49742016-06-22 10:04:46 +0200387 LOGERR(0, "User module retrieval callback failed!");
Michal Vasko99b0aad2015-12-01 12:28:51 +0100388 return NULL;
Michal Vasko82465962015-11-10 11:03:11 +0100389 }
Michal Vasko5a721fd2016-02-16 12:16:48 +0100390 module = lys_parse_mem(ctx, module_data, format);
Michal Vasko99b0aad2015-12-01 12:28:51 +0100391 if (module_data_free) {
392 module_data_free(module_data);
Michal Vasko82465962015-11-10 11:03:11 +0100393 }
Michal Vasko99b0aad2015-12-01 12:28:51 +0100394 } else {
Michal Vasko5a721fd2016-02-16 12:16:48 +0100395 module = lyp_search_file(ctx, NULL, name, revision, NULL);
Michal Vasko82465962015-11-10 11:03:11 +0100396 }
397
Michal Vasko5a721fd2016-02-16 12:16:48 +0100398 return module;
Michal Vasko82465962015-11-10 11:03:11 +0100399}
400
Michal Vaskod7957c02016-04-01 10:27:26 +0200401API const struct lys_module *
402ly_ctx_get_module_iter(const struct ly_ctx *ctx, uint32_t *idx)
403{
404 if (!ctx || !idx) {
405 ly_errno = LY_EINVAL;
406 return NULL;
407 }
408
409 if (*idx >= (unsigned)ctx->models.used) {
410 return NULL;
411 }
412
413 return ctx->models.list[(*idx)++];
414}
415
Michal Vasko209a6222015-10-16 09:51:07 +0200416static int
417ylib_feature(struct lyd_node *parent, struct lys_module *cur_mod)
418{
419 int i, j;
420
421 /* module features */
422 for (i = 0; i < cur_mod->features_size; ++i) {
423 if (!(cur_mod->features[i].flags & LYS_FENABLED)) {
424 continue;
425 }
426
Michal Vasko3e671b52015-10-23 16:23:15 +0200427 if (!lyd_new_leaf(parent, NULL, "feature", cur_mod->features[i].name)) {
Michal Vasko209a6222015-10-16 09:51:07 +0200428 return EXIT_FAILURE;
429 }
430 }
431
432 /* submodule features */
Radek Krejcic071c542016-01-27 14:57:51 +0100433 for (i = 0; i < cur_mod->inc_size && cur_mod->inc[i].submodule; ++i) {
Michal Vasko209a6222015-10-16 09:51:07 +0200434 for (j = 0; j < cur_mod->inc[i].submodule->features_size; ++j) {
435 if (!(cur_mod->inc[i].submodule->features[j].flags & LYS_FENABLED)) {
436 continue;
437 }
438
Michal Vasko3e671b52015-10-23 16:23:15 +0200439 if (!lyd_new_leaf(parent, NULL, "feature", cur_mod->inc[i].submodule->features[j].name)) {
Michal Vasko209a6222015-10-16 09:51:07 +0200440 return EXIT_FAILURE;
441 }
442 }
443 }
444
445 return EXIT_SUCCESS;
446}
447
448static int
Michal Vaskoff006c12016-02-17 11:15:19 +0100449ylib_deviation(struct lyd_node *parent, struct lys_module *cur_mod)
Michal Vasko97d8c6d2016-02-12 11:05:48 +0100450{
Michal Vaskoff006c12016-02-17 11:15:19 +0100451 int i;
Michal Vasko97d8c6d2016-02-12 11:05:48 +0100452 const char *revision;
Michal Vasko209a6222015-10-16 09:51:07 +0200453 struct lyd_node *cont;
454
Michal Vaskoff006c12016-02-17 11:15:19 +0100455 for (i = 0; i < cur_mod->imp_size; ++i) {
456 /* marks a deviating module */
457 if (cur_mod->imp[i].external == 2) {
458 revision = (cur_mod->imp[i].module->rev_size ? cur_mod->imp[i].module->rev[0].date : "");
Michal Vasko209a6222015-10-16 09:51:07 +0200459
Michal Vaskoff006c12016-02-17 11:15:19 +0100460 cont = lyd_new(parent, NULL, "deviation");
461 if (!cont) {
462 return EXIT_FAILURE;
Michal Vasko209a6222015-10-16 09:51:07 +0200463 }
Michal Vasko209a6222015-10-16 09:51:07 +0200464
Michal Vaskoff006c12016-02-17 11:15:19 +0100465 if (!lyd_new_leaf(cont, NULL, "name", cur_mod->imp[i].module->name)) {
466 return EXIT_FAILURE;
467 }
468 if (!lyd_new_leaf(cont, NULL, "revision", revision)) {
469 return EXIT_FAILURE;
Michal Vasko209a6222015-10-16 09:51:07 +0200470 }
471 }
472 }
473
474 return EXIT_SUCCESS;
475}
476
477static int
478ylib_submodules(struct lyd_node *parent, struct lys_module *cur_mod)
479{
480 int i;
Radek Krejcia77904e2016-02-25 16:23:45 +0100481 char *str;
Radek Krejci6e05cea2015-12-10 16:34:37 +0100482 struct lyd_node *cont, *item;
483
484 if (cur_mod->inc_size) {
485 cont = lyd_new(parent, NULL, "submodules");
486 }
Michal Vasko209a6222015-10-16 09:51:07 +0200487
Radek Krejcic071c542016-01-27 14:57:51 +0100488 for (i = 0; i < cur_mod->inc_size && cur_mod->inc[i].submodule; ++i) {
Radek Krejci6e05cea2015-12-10 16:34:37 +0100489 item = lyd_new(cont, NULL, "submodule");
490 if (!item) {
Michal Vasko209a6222015-10-16 09:51:07 +0200491 return EXIT_FAILURE;
492 }
493
Radek Krejci6e05cea2015-12-10 16:34:37 +0100494 if (!lyd_new_leaf(item, NULL, "name", cur_mod->inc[i].submodule->name)) {
Michal Vasko209a6222015-10-16 09:51:07 +0200495 return EXIT_FAILURE;
496 }
Radek Krejci6e05cea2015-12-10 16:34:37 +0100497 if (!lyd_new_leaf(item, NULL, "revision", (cur_mod->inc[i].submodule->rev_size ?
Michal Vasko3e671b52015-10-23 16:23:15 +0200498 cur_mod->inc[i].submodule->rev[0].date : ""))) {
Michal Vasko209a6222015-10-16 09:51:07 +0200499 return EXIT_FAILURE;
500 }
Radek Krejcia77904e2016-02-25 16:23:45 +0100501 if (cur_mod->inc[i].submodule->filepath) {
Radek Krejci95aa2012016-03-03 11:21:09 +0100502 if (asprintf(&str, "file://%s", cur_mod->inc[i].submodule->filepath) == -1) {
Radek Krejcia77904e2016-02-25 16:23:45 +0100503 LOGMEM;
504 return EXIT_FAILURE;
Radek Krejci6e65af92016-03-07 12:48:19 +0100505 } else if (!lyd_new_leaf(item, NULL, "schema", str)) {
Radek Krejci19f9ede2016-02-25 16:29:21 +0100506 free(str);
Radek Krejcia77904e2016-02-25 16:23:45 +0100507 return EXIT_FAILURE;
508 }
Radek Krejci19f9ede2016-02-25 16:29:21 +0100509 free(str);
Michal Vasko209a6222015-10-16 09:51:07 +0200510 }
511 }
512
513 return EXIT_SUCCESS;
514}
515
516API struct lyd_node *
517ly_ctx_info(struct ly_ctx *ctx)
518{
519 int i;
520 char id[8];
Radek Krejcia77904e2016-02-25 16:23:45 +0100521 char *str;
Michal Vasko1e62a092015-12-01 12:27:20 +0100522 const struct lys_module *mod;
Michal Vasko209a6222015-10-16 09:51:07 +0200523 struct lyd_node *root, *cont;
524
Michal Vasko7eccc6c2016-03-24 14:56:33 +0100525 if (!ctx) {
526 ly_errno = LY_EINVAL;
527 return NULL;
528 }
529
Radek Krejcibd9e8d22016-02-03 14:11:48 +0100530 mod = ly_ctx_get_module(ctx, "ietf-yang-library", IETF_YANG_LIB_REV);
531 if (!mod || !mod->data) {
532 LOGINT;
Michal Vasko209a6222015-10-16 09:51:07 +0200533 return NULL;
534 }
535
Radek Krejcibd9e8d22016-02-03 14:11:48 +0100536 root = lyd_new(NULL, mod, "modules-state");
Michal Vasko209a6222015-10-16 09:51:07 +0200537 if (!root) {
538 return NULL;
539 }
540
541 for (i = 0; i < ctx->models.used; ++i) {
542 cont = lyd_new(root, NULL, "module");
543 if (!cont) {
544 lyd_free(root);
545 return NULL;
546 }
547
Michal Vasko3e671b52015-10-23 16:23:15 +0200548 if (!lyd_new_leaf(cont, NULL, "name", ctx->models.list[i]->name)) {
Michal Vasko209a6222015-10-16 09:51:07 +0200549 lyd_free(root);
550 return NULL;
551 }
Michal Vasko3e671b52015-10-23 16:23:15 +0200552 if (!lyd_new_leaf(cont, NULL, "revision", (ctx->models.list[i]->rev_size ?
Michal Vasko209a6222015-10-16 09:51:07 +0200553 ctx->models.list[i]->rev[0].date : ""))) {
554 lyd_free(root);
555 return NULL;
556 }
Radek Krejcia77904e2016-02-25 16:23:45 +0100557 if (ctx->models.list[i]->filepath) {
Radek Krejci15412ca2016-03-03 11:16:52 +0100558 if (asprintf(&str, "file://%s", ctx->models.list[i]->filepath) == -1) {
Radek Krejcia77904e2016-02-25 16:23:45 +0100559 LOGMEM;
560 lyd_free(root);
561 return NULL;
562 } else if (!lyd_new_leaf(cont, NULL, "schema", str)) {
Radek Krejci19f9ede2016-02-25 16:29:21 +0100563 free(str);
Radek Krejcia77904e2016-02-25 16:23:45 +0100564 lyd_free(root);
565 return NULL;
566 }
Radek Krejci19f9ede2016-02-25 16:29:21 +0100567 free(str);
Michal Vasko209a6222015-10-16 09:51:07 +0200568 }
Michal Vasko3e671b52015-10-23 16:23:15 +0200569 if (!lyd_new_leaf(cont, NULL, "namespace", ctx->models.list[i]->ns)) {
Michal Vasko209a6222015-10-16 09:51:07 +0200570 lyd_free(root);
571 return NULL;
572 }
573 if (ylib_feature(cont, ctx->models.list[i])) {
574 lyd_free(root);
575 return NULL;
576 }
Michal Vaskoff006c12016-02-17 11:15:19 +0100577 if (ylib_deviation(cont, ctx->models.list[i])) {
Michal Vasko209a6222015-10-16 09:51:07 +0200578 lyd_free(root);
579 return NULL;
580 }
581 if (ctx->models.list[i]->implemented
Radek Krejcibd9e8d22016-02-03 14:11:48 +0100582 && !lyd_new_leaf(cont, NULL, "conformance-type", "implement")) {
Michal Vasko209a6222015-10-16 09:51:07 +0200583 lyd_free(root);
584 return NULL;
585 }
586 if (!ctx->models.list[i]->implemented
Radek Krejcibd9e8d22016-02-03 14:11:48 +0100587 && !lyd_new_leaf(cont, NULL, "conformance-type", "import")) {
Michal Vasko209a6222015-10-16 09:51:07 +0200588 lyd_free(root);
589 return NULL;
590 }
591 if (ylib_submodules(cont, ctx->models.list[i])) {
592 lyd_free(root);
593 return NULL;
594 }
595 }
596
597 sprintf(id, "%u", ctx->models.module_set_id);
Michal Vasko3e671b52015-10-23 16:23:15 +0200598 if (!lyd_new_leaf(root, mod, "module-set-id", id)) {
Michal Vasko209a6222015-10-16 09:51:07 +0200599 lyd_free(root);
600 return NULL;
601 }
602
Michal Vasko80bd80d2016-04-13 14:10:15 +0200603 if (lyd_validate(&root, LYD_OPT_NOSIBLINGS)) {
Michal Vasko209a6222015-10-16 09:51:07 +0200604 lyd_free(root);
605 return NULL;
606 }
607
608 return root;
609}
Michal Vasko3edeaf72016-02-11 13:17:43 +0100610
611API const struct lys_node *
Michal Vasko3547c532016-03-14 09:40:50 +0100612ly_ctx_get_node(struct ly_ctx *ctx, const struct lys_node *start, const char *nodeid)
Michal Vasko3edeaf72016-02-11 13:17:43 +0100613{
Michal Vaskoe733d682016-03-14 09:08:27 +0100614 const struct lys_node *node;
Michal Vasko3edeaf72016-02-11 13:17:43 +0100615
Michal Vasko3547c532016-03-14 09:40:50 +0100616 if (!ctx || !nodeid || ((nodeid[0] != '/') && !start)) {
Michal Vasko3edeaf72016-02-11 13:17:43 +0100617 ly_errno = LY_EINVAL;
618 return NULL;
619 }
620
Michal Vaskoe733d682016-03-14 09:08:27 +0100621 /* sets error and everything */
Michal Vasko9fd98e22016-04-07 15:44:19 +0200622 node = resolve_json_schema_nodeid(nodeid, ctx, start, 0);
623
624 return node;
625}
626
627API const struct lys_node *
628ly_ctx_get_node2(struct ly_ctx *ctx, const struct lys_node *start, const char *nodeid, int rpc_output)
629{
630 const struct lys_node *node;
631
632 if (!ctx || !nodeid || ((nodeid[0] != '/') && !start)) {
633 ly_errno = LY_EINVAL;
634 return NULL;
635 }
636
637 node = resolve_json_schema_nodeid(nodeid, ctx, start, (rpc_output ? 2 : 1));
Michal Vasko3edeaf72016-02-11 13:17:43 +0100638
Michal Vaskoe733d682016-03-14 09:08:27 +0100639 return node;
Michal Vasko3edeaf72016-02-11 13:17:43 +0100640}