blob: 54c516e57de1a5d7abeb6546c900c01e0cb1bdc1 [file] [log] [blame]
Radek Krejcida04f4a2015-05-21 12:54:09 +02001/**
2 * @file context.c
3 * @author Radek Krejci <rkrejci@cesnet.cz>
4 * @brief context implementation for libyang
5 *
6 * Copyright (c) 2015 CESNET, z.s.p.o.
7 *
Radek Krejci54f6fb32016-02-24 12:56:39 +01008 * This source code is licensed under BSD 3-Clause License (the "License").
9 * You may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
Michal Vasko8de098c2016-02-26 10:00:25 +010011 *
Radek Krejci54f6fb32016-02-24 12:56:39 +010012 * https://opensource.org/licenses/BSD-3-Clause
Radek Krejcida04f4a2015-05-21 12:54:09 +020013 */
14
15#define _GNU_SOURCE
Radek Krejcicf748252017-09-04 11:11:14 +020016#include <pthread.h>
Radek Krejcifd4e6e32015-08-10 15:00:51 +020017#include <stddef.h>
Radek Krejcida04f4a2015-05-21 12:54:09 +020018#include <stdlib.h>
19#include <string.h>
20#include <sys/types.h>
21#include <sys/stat.h>
22#include <unistd.h>
Michal Vasko6d2beea2018-08-14 08:34:21 +020023#include <limits.h>
Radek Krejcida04f4a2015-05-21 12:54:09 +020024#include <errno.h>
25#include <fcntl.h>
26
27#include "common.h"
28#include "context.h"
Michal Vasko6c810702018-03-14 16:23:21 +010029#include "hash_table.h"
Michal Vasko209a6222015-10-16 09:51:07 +020030#include "parser.h"
Radek Krejcibc9cf932015-07-30 11:09:39 +020031#include "tree_internal.h"
Radek Krejci83a4bac2017-02-07 15:53:04 +010032#include "resolve.h"
Radek Krejcida04f4a2015-05-21 12:54:09 +020033
Radek Krejci858ad952017-01-04 11:16:32 +010034/*
35 * counter for references to the extensions plugins (for the number of contexts)
36 * located in extensions.c
37 */
38extern unsigned int ext_plugins_ref;
39
Radek Krejci532e5e92017-02-22 12:59:24 +010040#define IETF_YANG_METADATA_PATH "../models/ietf-yang-metadata@2016-08-05.h"
41#define YANG_PATH "../models/yang@2017-02-20.h"
Michal Vasko8d054e42015-08-03 12:42:06 +020042#define IETF_INET_TYPES_PATH "../models/ietf-inet-types@2013-07-15.h"
Michal Vasko21181c42015-08-03 13:46:45 +020043#define IETF_YANG_TYPES_PATH "../models/ietf-yang-types@2013-07-15.h"
Radek Krejcidfb00d62017-09-06 09:39:35 +020044#define IETF_DATASTORES "../models/ietf-datastores@2017-08-17.h"
Michal Vaskoeb3bd0e2018-01-26 11:52:11 +010045#define IETF_YANG_LIB_PATH "../models/ietf-yang-library@2018-01-17.h"
46#define IETF_YANG_LIB_REV "2018-01-17"
Michal Vasko8d054e42015-08-03 12:42:06 +020047
Radek Krejci532e5e92017-02-22 12:59:24 +010048#include IETF_YANG_METADATA_PATH
49#include YANG_PATH
Michal Vasko8d054e42015-08-03 12:42:06 +020050#include IETF_INET_TYPES_PATH
Michal Vasko21181c42015-08-03 13:46:45 +020051#include IETF_YANG_TYPES_PATH
Radek Krejcidfb00d62017-09-06 09:39:35 +020052#include IETF_DATASTORES
Michal Vasko8d054e42015-08-03 12:42:06 +020053#include IETF_YANG_LIB_PATH
54
Radek Krejcidfb00d62017-09-06 09:39:35 +020055#define LY_INTERNAL_MODULE_COUNT 6
Radek Krejci03203412016-06-23 15:20:53 +020056static struct internal_modules_s {
57 const char *name;
58 const char *revision;
59 const char *data;
60 uint8_t implemented;
61 LYS_INFORMAT format;
Michal Vasko2d051a12017-04-21 09:28:57 +020062} internal_modules[LY_INTERNAL_MODULE_COUNT] = {
Radek Krejci532e5e92017-02-22 12:59:24 +010063 {"ietf-yang-metadata", "2016-08-05", (const char*)ietf_yang_metadata_2016_08_05_yin, 0, LYS_IN_YIN},
64 {"yang", "2017-02-20", (const char*)yang_2017_02_20_yin, 1, LYS_IN_YIN},
Radek Krejci03203412016-06-23 15:20:53 +020065 {"ietf-inet-types", "2013-07-15", (const char*)ietf_inet_types_2013_07_15_yin, 0, LYS_IN_YIN},
66 {"ietf-yang-types", "2013-07-15", (const char*)ietf_yang_types_2013_07_15_yin, 0, LYS_IN_YIN},
Radek Krejcidfb00d62017-09-06 09:39:35 +020067 /* ietf-datastores and ietf-yang-library must be right here at the end of the list! */
68 {"ietf-datastores", "2017-08-17", (const char*)ietf_datastores_2017_08_17_yin, 0, LYS_IN_YIN},
Michal Vaskoeb3bd0e2018-01-26 11:52:11 +010069 {"ietf-yang-library", IETF_YANG_LIB_REV, (const char*)ietf_yang_library_2018_01_17_yin, 1, LYS_IN_YIN}
Radek Krejci03203412016-06-23 15:20:53 +020070};
71
Radek Krejcidfb00d62017-09-06 09:39:35 +020072API unsigned int
73ly_ctx_internal_modules_count(struct ly_ctx *ctx)
74{
75 if (!ctx) {
76 return 0;
77 }
78 return ctx->internal_module_count;
79}
80
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020081API struct ly_ctx *
Radek Krejcidd3263a2017-07-15 11:50:09 +020082ly_ctx_new(const char *search_dir, int options)
Radek Krejcida04f4a2015-05-21 12:54:09 +020083{
Radek Krejcia8d111f2017-05-31 13:57:37 +020084 struct ly_ctx *ctx = NULL;
Michal Vasko7d7de952016-05-02 17:13:14 +020085 struct lys_module *module;
Radek Krejcia8d111f2017-05-31 13:57:37 +020086 char *cwd = NULL;
Igor Ternovsky9a10e1a2017-09-11 12:53:04 +100087 char *search_dir_list;
88 char *sep, *dir;
Igor Ternovsky6e6543d2017-09-12 10:37:28 +100089 int rc = EXIT_SUCCESS;
Radek Krejci03203412016-06-23 15:20:53 +020090 int i;
Radek Krejcida04f4a2015-05-21 12:54:09 +020091
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020092 ctx = calloc(1, sizeof *ctx);
Michal Vasko53b7da02018-02-13 15:28:42 +010093 LY_CHECK_ERR_RETURN(!ctx, LOGMEM(NULL), NULL);
Radek Krejcida04f4a2015-05-21 12:54:09 +020094
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020095 /* dictionary */
96 lydict_init(&ctx->dict);
Radek Krejcida04f4a2015-05-21 12:54:09 +020097
Radek Krejci858ad952017-01-04 11:16:32 +010098 /* plugins */
Michal Vaskoc6cd3f02018-03-02 14:07:42 +010099 ly_load_plugins();
Radek Krejci858ad952017-01-04 11:16:32 +0100100
Radek Krejcicf748252017-09-04 11:11:14 +0200101 /* initialize thread-specific key */
102 while ((i = pthread_key_create(&ctx->errlist_key, ly_err_free)) == EAGAIN);
103
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200104 /* models list */
105 ctx->models.list = calloc(16, sizeof *ctx->models.list);
Michal Vasko53b7da02018-02-13 15:28:42 +0100106 LY_CHECK_ERR_RETURN(!ctx->models.list, LOGMEM(NULL); free(ctx), NULL);
Radek Krejcidd3263a2017-07-15 11:50:09 +0200107 ctx->models.flags = options;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200108 ctx->models.used = 0;
109 ctx->models.size = 16;
110 if (search_dir) {
Igor Ternovsky9a10e1a2017-09-11 12:53:04 +1000111 search_dir_list = strdup(search_dir);
Michal Vasko53b7da02018-02-13 15:28:42 +0100112 LY_CHECK_ERR_GOTO(!search_dir_list, LOGMEM(NULL), error);
Igor Ternovsky9a10e1a2017-09-11 12:53:04 +1000113
Igor Ternovsky6e6543d2017-09-12 10:37:28 +1000114 for (dir = search_dir_list; (sep = strchr(dir, ':')) != NULL && rc == EXIT_SUCCESS; dir = sep + 1) {
Igor Ternovsky9a10e1a2017-09-11 12:53:04 +1000115 *sep = 0;
Igor Ternovsky6e6543d2017-09-12 10:37:28 +1000116 rc = ly_ctx_set_searchdir(ctx, dir);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200117 }
Igor Ternovsky6e6543d2017-09-12 10:37:28 +1000118 if (*dir && rc == EXIT_SUCCESS) {
119 rc = ly_ctx_set_searchdir(ctx, dir);
Radek Krejci15412ca2016-03-03 11:16:52 +0100120 }
Igor Ternovsky9a10e1a2017-09-11 12:53:04 +1000121 free(search_dir_list);
Igor Ternovsky6e6543d2017-09-12 10:37:28 +1000122 /* If ly_ctx_set_searchdir() failed, the error is already logged. Just exit */
123 if (rc != EXIT_SUCCESS) {
124 goto error;
125 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200126 }
Michal Vasko14719b22015-08-03 12:47:55 +0200127 ctx->models.module_set_id = 1;
128
Radek Krejci03203412016-06-23 15:20:53 +0200129 /* load internal modules */
Radek Krejcidfb00d62017-09-06 09:39:35 +0200130 if (options & LY_CTX_NOYANGLIBRARY) {
131 ctx->internal_module_count = LY_INTERNAL_MODULE_COUNT - 2;
132 } else {
133 ctx->internal_module_count = LY_INTERNAL_MODULE_COUNT;
134 }
135 for (i = 0; i < ctx->internal_module_count; i++) {
Radek Krejci03203412016-06-23 15:20:53 +0200136 module = (struct lys_module *)lys_parse_mem(ctx, internal_modules[i].data, internal_modules[i].format);
137 if (!module) {
Radek Krejcia8d111f2017-05-31 13:57:37 +0200138 goto error;
Radek Krejci03203412016-06-23 15:20:53 +0200139 }
140 module->implemented = internal_modules[i].implemented;
Michal Vasko8d054e42015-08-03 12:42:06 +0200141 }
Radek Krejcida04f4a2015-05-21 12:54:09 +0200142
Radek Krejcia8d111f2017-05-31 13:57:37 +0200143 /* cleanup */
144 free(cwd);
145
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200146 return ctx;
Radek Krejcia8d111f2017-05-31 13:57:37 +0200147
148error:
149 free(cwd);
150 ly_ctx_destroy(ctx, NULL);
151 return NULL;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200152}
153
Michal Vaskoeb3bd0e2018-01-26 11:52:11 +0100154static int
155ly_ctx_new_yl_legacy(struct ly_ctx *ctx, struct lyd_node *yltree)
Radek Krejci69333c92017-03-17 16:14:43 +0100156{
Michal Vasko60d400b2017-12-13 11:14:39 +0100157 unsigned int i, u;
Radek Krejci69333c92017-03-17 16:14:43 +0100158 struct lyd_node *module, *node;
Michal Vaskoeb3bd0e2018-01-26 11:52:11 +0100159 struct ly_set *set;
Radek Krejci69333c92017-03-17 16:14:43 +0100160 const char *name, *revision;
Radek Krejci5cb217d2017-03-25 16:07:52 -0500161 struct ly_set features = {0, 0, {NULL}};
Radek Krejci69333c92017-03-17 16:14:43 +0100162 const struct lys_module *mod;
Radek Krejci69333c92017-03-17 16:14:43 +0100163
Michal Vaskoeb3bd0e2018-01-26 11:52:11 +0100164 set = lyd_find_path(yltree, "/ietf-yang-library:yang-library/modules-state/module");
Michal Vasko60d400b2017-12-13 11:14:39 +0100165 if (!set) {
Michal Vaskoeb3bd0e2018-01-26 11:52:11 +0100166 return 1;
Michal Vasko60d400b2017-12-13 11:14:39 +0100167 }
168
Radek Krejci69333c92017-03-17 16:14:43 +0100169 /* process the data tree */
Michal Vasko60d400b2017-12-13 11:14:39 +0100170 for (i = 0; i < set->number; ++i) {
171 module = set->set.d[i];
Radek Krejci69333c92017-03-17 16:14:43 +0100172
173 /* initiate */
174 name = NULL;
175 revision = NULL;
176 ly_set_clean(&features);
177
178 LY_TREE_FOR(module->child, node) {
179 if (!strcmp(node->schema->name, "name")) {
180 name = ((struct lyd_node_leaf_list*)node)->value_str;
181 } else if (!strcmp(node->schema->name, "revision")) {
182 revision = ((struct lyd_node_leaf_list*)node)->value_str;
183 } else if (!strcmp(node->schema->name, "feature")) {
184 ly_set_add(&features, node, LY_SET_OPT_USEASLIST);
185 } else if (!strcmp(node->schema->name, "conformance-type") &&
186 ((struct lyd_node_leaf_list*)node)->value.enm->value) {
187 /* imported module - skip it, it will be loaded as a side effect
188 * of loading another module */
Michal Vasko60d400b2017-12-13 11:14:39 +0100189 continue;
Radek Krejci69333c92017-03-17 16:14:43 +0100190 }
191 }
192
193 /* use the gathered data to load the module */
194 mod = ly_ctx_load_module(ctx, name, revision);
195 if (!mod) {
Michal Vasko53b7da02018-02-13 15:28:42 +0100196 LOGERR(ctx, LY_EINVAL, "Unable to load module specified by yang library data.");
Michal Vaskoeb3bd0e2018-01-26 11:52:11 +0100197 ly_set_free(set);
198 return 1;
Radek Krejci69333c92017-03-17 16:14:43 +0100199 }
200
201 /* set features */
202 for (u = 0; u < features.number; u++) {
203 lys_features_enable(mod, ((struct lyd_node_leaf_list*)features.set.d[u])->value_str);
204 }
Radek Krejci69333c92017-03-17 16:14:43 +0100205 }
206
Michal Vaskoeb3bd0e2018-01-26 11:52:11 +0100207 ly_set_free(set);
208 return 0;
209}
210
211static struct ly_ctx *
212ly_ctx_new_yl_common(const char *search_dir, const char *input, LYD_FORMAT format, int options,
213 struct lyd_node* (*parser_func)(struct ly_ctx*, const char*, LYD_FORMAT, int,...))
214{
215 unsigned int i, u;
216 struct lyd_node *module, *node;
217 const char *name, *revision;
218 struct ly_set features = {0, 0, {NULL}};
219 const struct lys_module *mod;
220 struct lyd_node *yltree = NULL;
221 struct ly_ctx *ctx = NULL;
222 struct ly_set *set = NULL;
223
224 /* create empty (with internal modules including ietf-yang-library) context */
225 ctx = ly_ctx_new(search_dir, options);
226 if (!ctx) {
227 goto error;
228 }
229
230 /* parse yang library data tree */
231 yltree = parser_func(ctx, input, format, LYD_OPT_DATA, NULL);
232 if (!yltree) {
233 goto error;
234 }
235
236 set = lyd_find_path(yltree, "/ietf-yang-library:yang-library/module-set[1]/module");
237 if (!set) {
238 goto error;
239 }
240
241 if (set->number == 0) {
242 /* perhaps a legacy data tree? */
243 if (ly_ctx_new_yl_legacy(ctx, yltree)) {
244 goto error;
245 }
246 } else {
247 /* process the data tree */
248 for (i = 0; i < set->number; ++i) {
249 module = set->set.d[i];
250
251 /* initiate */
252 name = NULL;
253 revision = NULL;
254 ly_set_clean(&features);
255
256 LY_TREE_FOR(module->child, node) {
257 if (!strcmp(node->schema->name, "name")) {
258 name = ((struct lyd_node_leaf_list*)node)->value_str;
259 } else if (!strcmp(node->schema->name, "revision")) {
260 revision = ((struct lyd_node_leaf_list*)node)->value_str;
261 } else if (!strcmp(node->schema->name, "feature")) {
262 ly_set_add(&features, node->child, LY_SET_OPT_USEASLIST);
263 }
264 }
265
266 /* use the gathered data to load the module */
267 mod = ly_ctx_load_module(ctx, name, revision);
268 if (!mod) {
Michal Vasko53b7da02018-02-13 15:28:42 +0100269 LOGERR(NULL, LY_EINVAL, "Unable to load module specified by yang library data.");
Michal Vaskoeb3bd0e2018-01-26 11:52:11 +0100270 goto error;
271 }
272
273 /* set features */
274 for (u = 0; u < features.number; u++) {
275 lys_features_enable(mod, ((struct lyd_node_leaf_list*)features.set.d[u])->value_str);
276 }
277 }
278 }
279
Radek Krejci69333c92017-03-17 16:14:43 +0100280 if (0) {
281 /* skip context destroy in case of success */
282error:
283 ly_ctx_destroy(ctx, NULL);
284 ctx = NULL;
285 }
286
287 /* cleanup */
288 if (yltree) {
289 /* yang library data tree */
290 lyd_free_withsiblings(yltree);
291 }
Michal Vasko60d400b2017-12-13 11:14:39 +0100292 if (set) {
293 ly_set_free(set);
294 }
Radek Krejci69333c92017-03-17 16:14:43 +0100295
296 return ctx;
297}
298
299API struct ly_ctx *
Radek Krejcidd3263a2017-07-15 11:50:09 +0200300ly_ctx_new_ylpath(const char *search_dir, const char *path, LYD_FORMAT format, int options)
Radek Krejci69333c92017-03-17 16:14:43 +0100301{
Radek Krejcidd3263a2017-07-15 11:50:09 +0200302 return ly_ctx_new_yl_common(search_dir, path, format, options, lyd_parse_path);
Radek Krejci69333c92017-03-17 16:14:43 +0100303}
304
305API struct ly_ctx *
Radek Krejcidd3263a2017-07-15 11:50:09 +0200306ly_ctx_new_ylmem(const char *search_dir, const char *data, LYD_FORMAT format, int options)
Radek Krejci69333c92017-03-17 16:14:43 +0100307{
Radek Krejcidd3263a2017-07-15 11:50:09 +0200308 return ly_ctx_new_yl_common(search_dir, data, format, options, lyd_parse_mem);
309}
310
311static void
312ly_ctx_set_option(struct ly_ctx *ctx, int options)
313{
314 if (!ctx) {
315 return;
316 }
317
318 ctx->models.flags |= options;
319}
320
321static void
322ly_ctx_unset_option(struct ly_ctx *ctx, int options)
323{
324 if (!ctx) {
325 return;
326 }
327
328 ctx->models.flags &= ~options;
Radek Krejci69333c92017-03-17 16:14:43 +0100329}
330
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200331API void
Radek Krejci88b78422018-08-16 16:07:34 +0200332ly_ctx_set_disable_searchdirs(struct ly_ctx *ctx)
333{
Radek Krejci38f8cea2018-08-17 09:32:07 +0200334 ly_ctx_set_option(ctx, LY_CTX_DISABLE_SEARCHDIRS);
Radek Krejci88b78422018-08-16 16:07:34 +0200335}
336
337API void
338ly_ctx_unset_disable_searchdirs(struct ly_ctx *ctx)
339{
Radek Krejci38f8cea2018-08-17 09:32:07 +0200340 ly_ctx_unset_option(ctx, LY_CTX_DISABLE_SEARCHDIRS);
Radek Krejci88b78422018-08-16 16:07:34 +0200341}
342
343API void
Radek Krejcicf3b7ca2018-08-17 09:55:06 +0200344ly_ctx_set_disable_searchdir_cwd(struct ly_ctx *ctx)
345{
346 ly_ctx_set_option(ctx, LY_CTX_DISABLE_SEARCHDIR_CWD);
347}
348
349API void
350ly_ctx_unset_disable_searchdir_cwd(struct ly_ctx *ctx)
351{
352 ly_ctx_unset_option(ctx, LY_CTX_DISABLE_SEARCHDIR_CWD);
353}
354
355API void
Radek Krejci0c4a38f2018-08-28 15:50:23 +0200356ly_ctx_set_prefer_searchdirs(struct ly_ctx *ctx)
357{
358 ly_ctx_set_option(ctx, LY_CTX_PREFER_SEARCHDIRS);
359}
360
361API void
362ly_ctx_unset_prefer_searchdirs(struct ly_ctx *ctx)
363{
364 ly_ctx_unset_option(ctx, LY_CTX_PREFER_SEARCHDIRS);
365}
366
367API void
Radek Krejci819dd4b2017-03-07 15:35:48 +0100368ly_ctx_set_allimplemented(struct ly_ctx *ctx)
369{
Radek Krejcidd3263a2017-07-15 11:50:09 +0200370 ly_ctx_set_option(ctx, LY_CTX_ALLIMPLEMENTED);
Radek Krejci819dd4b2017-03-07 15:35:48 +0100371}
372
373API void
374ly_ctx_unset_allimplemented(struct ly_ctx *ctx)
375{
Radek Krejcidd3263a2017-07-15 11:50:09 +0200376 ly_ctx_unset_option(ctx, LY_CTX_ALLIMPLEMENTED);
377}
Radek Krejci819dd4b2017-03-07 15:35:48 +0100378
Radek Krejcidd3263a2017-07-15 11:50:09 +0200379API void
380ly_ctx_set_trusted(struct ly_ctx *ctx)
381{
382 ly_ctx_set_option(ctx, LY_CTX_TRUSTED);
383}
384
385API void
386ly_ctx_unset_trusted(struct ly_ctx *ctx)
387{
388 ly_ctx_unset_option(ctx, LY_CTX_TRUSTED);
Radek Krejci819dd4b2017-03-07 15:35:48 +0100389}
390
Igor Ternovsky6e6543d2017-09-12 10:37:28 +1000391API int
Radek Krejci4fb7d7d2018-08-17 10:08:59 +0200392ly_ctx_get_options(struct ly_ctx *ctx)
393{
394 return ctx->models.flags;
395}
396
397API int
Michal Vasko60ba9a62015-07-03 14:42:31 +0200398ly_ctx_set_searchdir(struct ly_ctx *ctx, const char *search_dir)
399{
Michal Vaskoaecdb212018-08-17 10:27:34 +0200400 char *new_dir = NULL;
Radek Krejcida9f8392017-03-25 19:40:56 -0500401 int index = 0;
402 void *r;
Igor Ternovsky6e6543d2017-09-12 10:37:28 +1000403 int rc = EXIT_FAILURE;
Michal Vasko60ba9a62015-07-03 14:42:31 +0200404
405 if (!ctx) {
Michal Vasko53b7da02018-02-13 15:28:42 +0100406 LOGARG;
Igor Ternovsky6e6543d2017-09-12 10:37:28 +1000407 return EXIT_FAILURE;
Michal Vasko60ba9a62015-07-03 14:42:31 +0200408 }
409
410 if (search_dir) {
Michal Vasko6d2beea2018-08-14 08:34:21 +0200411 if (access(search_dir, R_OK | X_OK)) {
Michal Vasko53b7da02018-02-13 15:28:42 +0100412 LOGERR(ctx, LY_ESYS, "Unable to use search directory \"%s\" (%s)",
Michal Vasko60ba9a62015-07-03 14:42:31 +0200413 search_dir, strerror(errno));
Michal Vasko6d2beea2018-08-14 08:34:21 +0200414 return EXIT_FAILURE;
Michal Vasko60ba9a62015-07-03 14:42:31 +0200415 }
Radek Krejcida9f8392017-03-25 19:40:56 -0500416
Michal Vaskoaecdb212018-08-17 10:27:34 +0200417 new_dir = realpath(search_dir, NULL);
418 LY_CHECK_ERR_GOTO(!new_dir, LOGERR(ctx, LY_ESYS, "realpath() call failed (%s).", strerror(errno)), cleanup);
Radek Krejcida9f8392017-03-25 19:40:56 -0500419 if (!ctx->models.search_paths) {
420 ctx->models.search_paths = malloc(2 * sizeof *ctx->models.search_paths);
Michal Vasko53b7da02018-02-13 15:28:42 +0100421 LY_CHECK_ERR_GOTO(!ctx->models.search_paths, LOGMEM(ctx), cleanup);
Radek Krejcida9f8392017-03-25 19:40:56 -0500422 index = 0;
423 } else {
Radek Krejci426ea2b2017-06-13 12:41:51 +0200424 for (index = 0; ctx->models.search_paths[index]; index++) {
425 /* check for duplicities */
Michal Vaskoaecdb212018-08-17 10:27:34 +0200426 if (!strcmp(new_dir, ctx->models.search_paths[index])) {
Radek Krejci426ea2b2017-06-13 12:41:51 +0200427 /* path is already present */
Radek Krejci426ea2b2017-06-13 12:41:51 +0200428 goto success;
429 }
430 }
Radek Krejcida9f8392017-03-25 19:40:56 -0500431 r = realloc(ctx->models.search_paths, (index + 2) * sizeof *ctx->models.search_paths);
Michal Vasko53b7da02018-02-13 15:28:42 +0100432 LY_CHECK_ERR_GOTO(!r, LOGMEM(ctx), cleanup);
Radek Krejcida9f8392017-03-25 19:40:56 -0500433 ctx->models.search_paths = r;
434 }
Michal Vaskoaecdb212018-08-17 10:27:34 +0200435 ctx->models.search_paths[index] = new_dir;
436 new_dir = NULL;
Radek Krejcida9f8392017-03-25 19:40:56 -0500437 ctx->models.search_paths[index + 1] = NULL;
Michal Vasko3eff9322015-11-10 11:02:30 +0100438
Radek Krejci426ea2b2017-06-13 12:41:51 +0200439success:
Igor Ternovsky6e6543d2017-09-12 10:37:28 +1000440 rc = EXIT_SUCCESS;
Radek Krejci9287c702017-09-12 10:32:24 +0200441 } else {
442 /* consider that no change is not actually an error */
443 return EXIT_SUCCESS;
Michal Vasko60ba9a62015-07-03 14:42:31 +0200444 }
Radek Krejcia8d111f2017-05-31 13:57:37 +0200445
446cleanup:
Michal Vaskoaecdb212018-08-17 10:27:34 +0200447 free(new_dir);
Igor Ternovsky6e6543d2017-09-12 10:37:28 +1000448 return rc;
Michal Vasko60ba9a62015-07-03 14:42:31 +0200449}
450
Radek Krejci426ea2b2017-06-13 12:41:51 +0200451API const char * const *
452ly_ctx_get_searchdirs(const struct ly_ctx *ctx)
Radek Krejci5a797572015-10-21 15:45:45 +0200453{
Radek Krejciee554172016-12-14 10:29:06 +0100454 if (!ctx) {
Michal Vasko53b7da02018-02-13 15:28:42 +0100455 LOGARG;
Radek Krejciee554172016-12-14 10:29:06 +0100456 return NULL;
457 }
Radek Krejci426ea2b2017-06-13 12:41:51 +0200458 return (const char * const *)ctx->models.search_paths;
Radek Krejcida9f8392017-03-25 19:40:56 -0500459}
460
461API void
Radek Krejcidb4e9ff2017-06-13 16:26:14 +0200462ly_ctx_unset_searchdirs(struct ly_ctx *ctx, int index)
Radek Krejcida9f8392017-03-25 19:40:56 -0500463{
464 int i;
465
466 if (!ctx->models.search_paths) {
467 return;
468 }
469
470 for (i = 0; ctx->models.search_paths[i]; i++) {
Radek Krejcidb4e9ff2017-06-13 16:26:14 +0200471 if (index < 0 || index == i) {
472 free(ctx->models.search_paths[i]);
473 ctx->models.search_paths[i] = NULL;
474 } else if (i > index) {
475 ctx->models.search_paths[i - 1] = ctx->models.search_paths[i];
476 ctx->models.search_paths[i] = NULL;
477 }
Radek Krejcida9f8392017-03-25 19:40:56 -0500478 }
Radek Krejcidb4e9ff2017-06-13 16:26:14 +0200479 if (index < 0 || !ctx->models.search_paths[0]) {
480 free(ctx->models.search_paths);
481 ctx->models.search_paths = NULL;
482 }
Radek Krejci5a797572015-10-21 15:45:45 +0200483}
484
Michal Vasko60ba9a62015-07-03 14:42:31 +0200485API void
Radek Krejcifa0b5e02016-02-04 13:57:03 +0100486ly_ctx_destroy(struct ly_ctx *ctx, void (*private_destructor)(const struct lys_node *node, void *priv))
Radek Krejcida04f4a2015-05-21 12:54:09 +0200487{
Radek Krejcida9f8392017-03-25 19:40:56 -0500488 int i;
489
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200490 if (!ctx) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200491 return;
492 }
Radek Krejcida04f4a2015-05-21 12:54:09 +0200493
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200494 /* models list */
Radek Krejcic436a232017-02-08 14:43:11 +0100495 for (; ctx->models.used > 0; ctx->models.used--) {
Radek Krejcifc8411a2017-02-03 10:26:05 +0100496 /* remove the applied deviations and augments */
Radek Krejcic436a232017-02-08 14:43:11 +0100497 lys_sub_module_remove_devs_augs(ctx->models.list[ctx->models.used - 1]);
Radek Krejcifc8411a2017-02-03 10:26:05 +0100498 /* remove the module */
Michal Vasko10681e82018-01-16 14:54:16 +0100499 lys_free(ctx->models.list[ctx->models.used - 1], private_destructor, 1, 0);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200500 }
Radek Krejcida9f8392017-03-25 19:40:56 -0500501 if (ctx->models.search_paths) {
502 for(i = 0; ctx->models.search_paths[i]; i++) {
503 free(ctx->models.search_paths[i]);
504 }
505 free(ctx->models.search_paths);
506 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200507 free(ctx->models.list);
Radek Krejcida04f4a2015-05-21 12:54:09 +0200508
Radek Krejcicf748252017-09-04 11:11:14 +0200509 /* clean the error list */
510 ly_err_clean(ctx, 0);
511 pthread_key_delete(ctx->errlist_key);
512
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200513 /* dictionary */
514 lydict_clean(&ctx->dict);
Radek Krejcida04f4a2015-05-21 12:54:09 +0200515
Radek Krejci858ad952017-01-04 11:16:32 +0100516 /* plugins - will be removed only if this is the last context */
Michal Vaskoc6cd3f02018-03-02 14:07:42 +0100517 ly_clean_plugins();
Radek Krejci858ad952017-01-04 11:16:32 +0100518
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200519 free(ctx);
Radek Krejcida04f4a2015-05-21 12:54:09 +0200520}
521
Michal Vasko1e62a092015-12-01 12:27:20 +0100522API const struct lys_submodule *
Radek Krejci62f0da72016-03-07 11:35:43 +0100523ly_ctx_get_submodule2(const struct lys_module *main_module, const char *submodule)
524{
Radek Krejcid4c1d0f2017-01-19 16:11:38 +0100525 const struct lys_submodule *result;
Radek Krejci62f0da72016-03-07 11:35:43 +0100526 int i;
527
528 if (!main_module || !submodule) {
Michal Vasko53b7da02018-02-13 15:28:42 +0100529 LOGARG;
Radek Krejci62f0da72016-03-07 11:35:43 +0100530 return NULL;
531 }
532
533 /* search in submodules list */
534 for (i = 0; i < main_module->inc_size; i++) {
535 result = main_module->inc[i].submodule;
Radek Krejcid4c1d0f2017-01-19 16:11:38 +0100536 if (ly_strequal(submodule, result->name, 0)) {
Radek Krejci62f0da72016-03-07 11:35:43 +0100537 return result;
538 }
Radek Krejcid4c1d0f2017-01-19 16:11:38 +0100539
540 /* in YANG 1.1 all the submodules must be included in the main module, so we are done.
541 * YANG 1.0 allows (is unclear about denying it) to include a submodule only in another submodule
542 * but when libyang parses such a module it adds the include into the main module so we are also done.
543 */
Radek Krejci62f0da72016-03-07 11:35:43 +0100544 }
545
546 return NULL;
547}
548
549API const struct lys_submodule *
Michal Vaskof6d94c62016-04-05 11:21:54 +0200550ly_ctx_get_submodule(const struct ly_ctx *ctx, const char *module, const char *revision, const char *submodule,
551 const char *sub_revision)
Radek Krejciefaeba32015-05-27 14:30:57 +0200552{
Radek Krejcie7973552016-03-07 08:12:01 +0100553 const struct lys_module *mainmod;
Michal Vaskof6d94c62016-04-05 11:21:54 +0200554 const struct lys_submodule *ret = NULL, *submod;
555 uint32_t idx = 0;
Radek Krejciefaeba32015-05-27 14:30:57 +0200556
Michal Vaskof6d94c62016-04-05 11:21:54 +0200557 if (!ctx || !submodule || (revision && !module)) {
Michal Vasko53b7da02018-02-13 15:28:42 +0100558 LOGARG;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200559 return NULL;
560 }
Radek Krejciefaeba32015-05-27 14:30:57 +0200561
Michal Vaskof6d94c62016-04-05 11:21:54 +0200562 while ((mainmod = ly_ctx_get_module_iter(ctx, &idx))) {
563 if (module && strcmp(mainmod->name, module)) {
564 /* main module name does not match */
565 continue;
566 }
567
568 if (revision && (!mainmod->rev || strcmp(revision, mainmod->rev[0].date))) {
569 /* main module revision does not match */
570 continue;
571 }
572
573 submod = ly_ctx_get_submodule2(mainmod, submodule);
574 if (!submod) {
575 continue;
576 }
577
578 if (!sub_revision) {
579 /* store only if newer */
580 if (ret) {
581 if (submod->rev && (!ret->rev || (strcmp(submod->rev[0].date, ret->rev[0].date) > 0))) {
582 ret = submod;
583 }
584 } else {
585 ret = submod;
586 }
587 } else {
588 /* store only if revision matches, we are done if it does */
589 if (!submod->rev) {
590 continue;
591 } else if (!strcmp(sub_revision, submod->rev[0].date)) {
592 ret = submod;
593 break;
594 }
595 }
Radek Krejcia7533f22016-03-07 07:37:45 +0100596 }
Radek Krejcic071c542016-01-27 14:57:51 +0100597
Michal Vaskof6d94c62016-04-05 11:21:54 +0200598 return ret;
Radek Krejciefaeba32015-05-27 14:30:57 +0200599}
600
Michal Vasko1e62a092015-12-01 12:27:20 +0100601static const struct lys_module *
Michal Vasko53b7da02018-02-13 15:28:42 +0100602ly_ctx_get_module_by(const struct ly_ctx *ctx, const char *key, size_t key_len, int offset, const char *revision,
603 int with_disabled, int implemented)
Radek Krejciefaeba32015-05-27 14:30:57 +0200604{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200605 int i;
Michal Vasko53b7da02018-02-13 15:28:42 +0100606 char *val;
Radek Krejcib8048692015-08-05 13:36:34 +0200607 struct lys_module *result = NULL;
Radek Krejciefaeba32015-05-27 14:30:57 +0200608
Radek Krejcifd4e6e32015-08-10 15:00:51 +0200609 if (!ctx || !key) {
Michal Vasko53b7da02018-02-13 15:28:42 +0100610 LOGARG;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200611 return NULL;
612 }
Radek Krejciefaeba32015-05-27 14:30:57 +0200613
Radek Krejcidce51452015-06-16 15:20:08 +0200614 for (i = 0; i < ctx->models.used; i++) {
Radek Krejci0ec51da2016-12-14 16:42:03 +0100615 if (!with_disabled && ctx->models.list[i]->disabled) {
616 /* skip the disabled modules */
617 continue;
618 }
Radek Krejcifd4e6e32015-08-10 15:00:51 +0200619 /* use offset to get address of the pointer to string (char**), remember that offset is in
620 * bytes, so we have to cast the pointer to the module to (char*), finally, we want to have
621 * string not the pointer to string
622 */
Michal Vasko53b7da02018-02-13 15:28:42 +0100623 val = *(char **)(((char *)ctx->models.list[i]) + offset);
624 if (!ctx->models.list[i] || (!key_len && strcmp(key, val)) || (key_len && (strncmp(key, val, key_len) || val[key_len]))) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200625 continue;
626 }
Radek Krejciefaeba32015-05-27 14:30:57 +0200627
Radek Krejcif647e612015-07-30 11:36:07 +0200628 if (!revision) {
629 /* compare revisons and remember the newest one */
630 if (result) {
631 if (!ctx->models.list[i]->rev_size) {
632 /* the current have no revision, keep the previous with some revision */
633 continue;
634 }
635 if (result->rev_size && strcmp(ctx->models.list[i]->rev[0].date, result->rev[0].date) < 0) {
636 /* the previous found matching module has a newer revision */
637 continue;
638 }
639 }
Radek Krejcidfb00d62017-09-06 09:39:35 +0200640 if (implemented) {
641 if (ctx->models.list[i]->implemented) {
642 /* we have the implemented revision */
643 result = ctx->models.list[i];
644 break;
645 } else {
646 /* do not remember the result, we are supposed to return the implemented revision
647 * not the newest one */
648 continue;
649 }
650 }
Radek Krejcif647e612015-07-30 11:36:07 +0200651
652 /* remember the current match and search for newer version */
653 result = ctx->models.list[i];
654 } else {
655 if (ctx->models.list[i]->rev_size && !strcmp(revision, ctx->models.list[i]->rev[0].date)) {
656 /* matching revision */
Michal Vasko97586502015-08-12 14:32:18 +0200657 result = ctx->models.list[i];
658 break;
Radek Krejcif647e612015-07-30 11:36:07 +0200659 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200660 }
661 }
Radek Krejciefaeba32015-05-27 14:30:57 +0200662
Radek Krejcif647e612015-07-30 11:36:07 +0200663 return result;
Radek Krejcifd4e6e32015-08-10 15:00:51 +0200664
665}
666
Michal Vasko1e62a092015-12-01 12:27:20 +0100667API const struct lys_module *
Radek Krejcidfb00d62017-09-06 09:39:35 +0200668ly_ctx_get_module_by_ns(const struct ly_ctx *ctx, const char *ns, const char *revision, int implemented)
Radek Krejcifd4e6e32015-08-10 15:00:51 +0200669{
Michal Vasko53b7da02018-02-13 15:28:42 +0100670 return ly_ctx_get_module_by(ctx, ns, 0, offsetof(struct lys_module, ns), revision, 0, implemented);
Radek Krejcifd4e6e32015-08-10 15:00:51 +0200671}
672
Michal Vasko1e62a092015-12-01 12:27:20 +0100673API const struct lys_module *
Radek Krejcidfb00d62017-09-06 09:39:35 +0200674ly_ctx_get_module(const struct ly_ctx *ctx, const char *name, const char *revision, int implemented)
Radek Krejcifd4e6e32015-08-10 15:00:51 +0200675{
Michal Vasko53b7da02018-02-13 15:28:42 +0100676 return ly_ctx_get_module_by(ctx, name, 0, offsetof(struct lys_module, name), revision, 0, implemented);
677}
678
679const struct lys_module *
680ly_ctx_nget_module(const struct ly_ctx *ctx, const char *name, size_t name_len, const char *revision, int implemented)
681{
682 return ly_ctx_get_module_by(ctx, name, name_len, offsetof(struct lys_module, name), revision, 0, implemented);
Radek Krejcida04f4a2015-05-21 12:54:09 +0200683}
Michal Vasko3ec07dc2015-06-30 15:51:30 +0200684
Radek Krejci21601a32016-03-07 11:39:27 +0100685API const struct lys_module *
686ly_ctx_get_module_older(const struct ly_ctx *ctx, const struct lys_module *module)
687{
688 int i;
689 const struct lys_module *result = NULL, *iter;
690
691 if (!ctx || !module || !module->rev_size) {
Michal Vasko53b7da02018-02-13 15:28:42 +0100692 LOGARG;
Radek Krejci21601a32016-03-07 11:39:27 +0100693 return NULL;
694 }
695
696
697 for (i = 0; i < ctx->models.used; i++) {
698 iter = ctx->models.list[i];
Radek Krejci0ec51da2016-12-14 16:42:03 +0100699 if (iter->disabled) {
700 /* skip the disabled modules */
701 continue;
702 }
Radek Krejci21601a32016-03-07 11:39:27 +0100703 if (iter == module || !iter->rev_size) {
704 /* iter is the module itself or iter has no revision */
705 continue;
706 }
707 if (!ly_strequal(module->name, iter->name, 0)) {
708 /* different module */
709 continue;
710 }
711 if (strcmp(iter->rev[0].date, module->rev[0].date) < 0) {
712 /* iter is older than module */
713 if (result) {
714 if (strcmp(iter->rev[0].date, result->rev[0].date) > 0) {
715 /* iter is newer than current result */
716 result = iter;
717 }
718 } else {
719 result = iter;
720 }
721 }
722 }
723
724 return result;
725}
726
Michal Vasko99b0aad2015-12-01 12:28:51 +0100727API void
Michal Vaskoca28aab2017-01-13 13:50:12 +0100728ly_ctx_set_module_imp_clb(struct ly_ctx *ctx, ly_module_imp_clb clb, void *user_data)
Michal Vasko82465962015-11-10 11:03:11 +0100729{
Michal Vaskoad9f92a2017-04-06 09:49:07 +0200730 if (!ctx) {
Michal Vasko53b7da02018-02-13 15:28:42 +0100731 LOGARG;
Michal Vaskoad9f92a2017-04-06 09:49:07 +0200732 return;
733 }
734
Michal Vaskof53187d2017-01-13 13:23:14 +0100735 ctx->imp_clb = clb;
736 ctx->imp_clb_data = user_data;
Michal Vasko99b0aad2015-12-01 12:28:51 +0100737}
738
Michal Vaskof53187d2017-01-13 13:23:14 +0100739API ly_module_imp_clb
Michal Vaskoca28aab2017-01-13 13:50:12 +0100740ly_ctx_get_module_imp_clb(const struct ly_ctx *ctx, void **user_data)
Michal Vasko99b0aad2015-12-01 12:28:51 +0100741{
Radek Krejciee554172016-12-14 10:29:06 +0100742 if (!ctx) {
Michal Vasko53b7da02018-02-13 15:28:42 +0100743 LOGARG;
Radek Krejciee554172016-12-14 10:29:06 +0100744 return NULL;
745 }
746
Michal Vasko99b0aad2015-12-01 12:28:51 +0100747 if (user_data) {
Michal Vaskof53187d2017-01-13 13:23:14 +0100748 *user_data = ctx->imp_clb_data;
Michal Vasko99b0aad2015-12-01 12:28:51 +0100749 }
Michal Vaskof53187d2017-01-13 13:23:14 +0100750 return ctx->imp_clb;
751}
752
753API void
Michal Vaskoca28aab2017-01-13 13:50:12 +0100754ly_ctx_set_module_data_clb(struct ly_ctx *ctx, ly_module_data_clb clb, void *user_data)
Michal Vaskof53187d2017-01-13 13:23:14 +0100755{
Michal Vaskoad9f92a2017-04-06 09:49:07 +0200756 if (!ctx) {
Michal Vasko53b7da02018-02-13 15:28:42 +0100757 LOGARG;
Michal Vaskoad9f92a2017-04-06 09:49:07 +0200758 return;
759 }
760
Michal Vaskof53187d2017-01-13 13:23:14 +0100761 ctx->data_clb = clb;
762 ctx->data_clb_data = user_data;
763}
764
765API ly_module_data_clb
Michal Vaskoca28aab2017-01-13 13:50:12 +0100766ly_ctx_get_module_data_clb(const struct ly_ctx *ctx, void **user_data)
Michal Vaskof53187d2017-01-13 13:23:14 +0100767{
Michal Vaskoad9f92a2017-04-06 09:49:07 +0200768 if (!ctx) {
Michal Vasko53b7da02018-02-13 15:28:42 +0100769 LOGARG;
Michal Vaskoad9f92a2017-04-06 09:49:07 +0200770 return NULL;
771 }
772
Michal Vaskof53187d2017-01-13 13:23:14 +0100773 if (user_data) {
774 *user_data = ctx->data_clb_data;
775 }
776 return ctx->data_clb;
Michal Vasko99b0aad2015-12-01 12:28:51 +0100777}
778
Michal Vaskoe385e902018-07-02 10:15:11 +0200779#ifdef LY_ENABLED_LYD_PRIV
780
781API void
782ly_ctx_set_priv_dup_clb(struct ly_ctx *ctx, void *(*priv_dup_clb)(const void *priv))
783{
784 ctx->priv_dup_clb = priv_dup_clb;
785}
786
787#endif
788
Radek Krejci72cdfac2018-08-15 14:47:33 +0200789/* if module is !NULL, then the function searches for submodule */
790static struct lys_module *
791ly_ctx_load_localfile(struct ly_ctx *ctx, struct lys_module *module, const char *name, const char *revision,
792 int implement, struct unres_schema *unres)
793{
794 size_t len;
795 int fd, i;
796 char *filepath = NULL, *dot, *rev, *filename;
797 LYS_INFORMAT format;
798 struct lys_module *result = NULL;
799
Radek Krejcicf3b7ca2018-08-17 09:55:06 +0200800 if (lys_search_localfile(ly_ctx_get_searchdirs(ctx), !(ctx->models.flags & LY_CTX_DISABLE_SEARCHDIR_CWD), name, revision,
801 &filepath, &format)) {
Radek Krejci72cdfac2018-08-15 14:47:33 +0200802 goto cleanup;
803 } else if (!filepath) {
804 if (!module && !revision) {
805 /* otherwise the module would be already taken from the context */
806 result = (struct lys_module *)ly_ctx_get_module(ctx, name, NULL, 0);
807 }
808 if (!result) {
809 LOGERR(ctx, LY_ESYS, "Data model \"%s\" not found.", name);
810 }
811 return result;
812 }
813
814 LOGVRB("Loading schema from \"%s\" file.", filepath);
815
816 /* cut the format for now */
817 dot = strrchr(filepath, '.');
818 dot[1] = '\0';
819
820 /* check that the same file was not already loaded - it make sense only in case of loading the newest revision,
821 * search also in disabled module - if the matching module is disabled, it will be enabled instead of loading it */
822 if (!revision) {
823 for (i = 0; i < ctx->models.used; ++i) {
824 if (ctx->models.list[i]->filepath && !strcmp(name, ctx->models.list[i]->name)
825 && !strncmp(filepath, ctx->models.list[i]->filepath, strlen(filepath))) {
826 result = ctx->models.list[i];
827 if (implement && !result->implemented) {
828 /* make it implemented now */
829 if (lys_set_implemented(result)) {
830 result = NULL;
831 }
832 } else if (result->disabled) {
833 lys_set_enabled(result);
834 }
835
836 goto cleanup;
837 }
838 }
839 }
840
841 /* add the format back */
842 dot[1] = 'y';
843
844 /* open the file */
845 fd = open(filepath, O_RDONLY);
846 if (fd < 0) {
847 LOGERR(ctx, LY_ESYS, "Unable to open data model file \"%s\" (%s).",
848 filepath, strerror(errno));
849 goto cleanup;
850 }
851
852 if (module) {
853 result = (struct lys_module *)lys_sub_parse_fd(module, fd, format, unres);
854 } else {
855 result = (struct lys_module *)lys_parse_fd_(ctx, fd, format, revision, implement);
856 }
857 close(fd);
858
859 if (!result) {
860 goto cleanup;
861 }
862
863 /* check that name and revision match filename */
864 filename = strrchr(filepath, '/');
865 if (!filename) {
866 filename = filepath;
867 } else {
868 filename++;
869 }
870 rev = strchr(filename, '@');
871 /* name */
872 len = strlen(result->name);
873 if (strncmp(filename, result->name, len) ||
874 ((rev && rev != &filename[len]) || (!rev && dot != &filename[len]))) {
875 LOGWRN(ctx, "File name \"%s\" does not match module name \"%s\".", filename, result->name);
876 }
877 if (rev) {
878 len = dot - ++rev;
879 if (!result->rev_size || len != 10 || strncmp(result->rev[0].date, rev, len)) {
880 LOGWRN(ctx, "File name \"%s\" does not match module revision \"%s\".", filename,
881 result->rev_size ? result->rev[0].date : "none");
882 }
883 }
884
Alexandre Snarskii8e5e0712018-09-03 18:35:38 +0300885 if (!result->filepath) {
886 char rpath[PATH_MAX];
Alexandre Snarskii12b22182018-09-04 17:12:28 +0300887 if (realpath(filepath, rpath) != NULL) {
Alexandre Snarskii8e5e0712018-09-03 18:35:38 +0300888 result->filepath = lydict_insert(ctx, rpath, 0);
Alexandre Snarskii12b22182018-09-04 17:12:28 +0300889 } else {
890 result->filepath = lydict_insert(ctx, filepath, 0);
891 }
Alexandre Snarskii8e5e0712018-09-03 18:35:38 +0300892 }
893
Radek Krejci72cdfac2018-08-15 14:47:33 +0200894 /* success */
895cleanup:
896 free(filepath);
897 return result;
898}
899
Radek Krejci0c4a38f2018-08-28 15:50:23 +0200900static struct lys_module *
901ly_ctx_load_sub_module_clb(struct ly_ctx *ctx, struct lys_module *module, const char *name, const char *revision,
902 int implement, struct unres_schema *unres)
903{
904 struct lys_module *mod = NULL;
905 char *module_data = NULL;
906 LYS_INFORMAT format = LYS_IN_UNKNOWN;
Jan Kundrát51823852018-09-06 17:17:36 +0200907 void (*module_data_free)(void *module_data, void *user_data) = NULL;
Radek Krejci0c4a38f2018-08-28 15:50:23 +0200908
909 ly_errno = LY_SUCCESS;
910 if (module) {
911 mod = lys_main_module(module);
912 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);
913 } else {
914 module_data = ctx->imp_clb(name, revision, NULL, NULL, ctx->imp_clb_data, &format, &module_data_free);
915 }
916 if (!module_data && (ly_errno != LY_SUCCESS)) {
917 /* callback encountered an error, do not change it */
918 LOGERR(ctx, ly_errno, "User module retrieval callback failed!");
919 return NULL;
920 }
921
922 if (module_data) {
923 /* we got the module from the callback */
924 if (module) {
925 mod = (struct lys_module *)lys_sub_parse_mem(module, module_data, format, unres);
926 } else {
927 mod = (struct lys_module *)lys_parse_mem_(ctx, module_data, format, NULL, 0, implement);
928 }
929
930 if (module_data_free) {
Jan Kundrát51823852018-09-06 17:17:36 +0200931 module_data_free(module_data, ctx->imp_clb_data);
Radek Krejci0c4a38f2018-08-28 15:50:23 +0200932 }
933 }
934
935 return mod;
936}
937
Radek Krejcibf4e4652016-10-21 15:44:13 +0200938const struct lys_module *
Michal Vasko84475152016-07-25 16:16:25 +0200939ly_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 +0200940 int implement, struct unres_schema *unres)
Michal Vasko99b0aad2015-12-01 12:28:51 +0100941{
Michal Vaskode701862018-08-17 10:27:49 +0200942 struct lys_module *mod = NULL;
Radek Krejci03203412016-06-23 15:20:53 +0200943 int i;
Michal Vasko82465962015-11-10 11:03:11 +0100944
Michal Vasko84475152016-07-25 16:16:25 +0200945 if (!module) {
Radek Krejcibf4e4652016-10-21 15:44:13 +0200946 /* exception for internal modules */
Radek Krejcidfb00d62017-09-06 09:39:35 +0200947 for (i = 0; i < ctx->internal_module_count; i++) {
Michal Vasko84475152016-07-25 16:16:25 +0200948 if (ly_strequal(name, internal_modules[i].name, 0)) {
949 if (!revision || ly_strequal(revision, internal_modules[i].revision, 0)) {
950 /* return internal module */
Radek Krejcidfb00d62017-09-06 09:39:35 +0200951 return (struct lys_module *)ly_ctx_get_module(ctx, name, revision, 0);
Michal Vasko84475152016-07-25 16:16:25 +0200952 }
Radek Krejci03203412016-06-23 15:20:53 +0200953 }
954 }
Michal Vasko8f3160e2017-09-27 11:25:26 +0200955 /* try to get the schema from the context (with or without revision),
956 * include the disabled modules in the search to avoid their duplication,
957 * they are enabled by the subsequent call to lys_set_implemented() */
958 for (i = ctx->internal_module_count, mod = NULL; i < ctx->models.used; i++) {
959 mod = ctx->models.list[i]; /* shortcut */
960 if (ly_strequal(name, mod->name, 0)) {
961 if (revision && mod->rev_size && !strcmp(revision, mod->rev[0].date)) {
962 /* the specific revision was already loaded */
963 break;
964 } else if (!revision && mod->latest_revision) {
965 /* the latest revision of this module was already loaded */
Radek Krejci0ec51da2016-12-14 16:42:03 +0100966 break;
Radek Krejci44564912017-10-31 16:49:29 +0100967 } else if (implement && mod->implemented && !revision) {
968 /* we are not able to implement another module, so consider this module as the latest one */
969 break;
Radek Krejci0ec51da2016-12-14 16:42:03 +0100970 }
Michal Vasko8f3160e2017-09-27 11:25:26 +0200971 }
972 mod = NULL;
973 }
974 if (mod) {
975 /* module must be enabled */
976 if (mod->disabled) {
977 lys_set_enabled(mod);
978 }
979 /* module is supposed to be implemented */
980 if (implement && lys_set_implemented(mod)) {
981 /* the schema cannot be implemented */
Radek Krejci0ec51da2016-12-14 16:42:03 +0100982 mod = NULL;
983 }
Michal Vasko8f3160e2017-09-27 11:25:26 +0200984 return mod;
Radek Krejcibf4e4652016-10-21 15:44:13 +0200985 }
Radek Krejci03203412016-06-23 15:20:53 +0200986 }
987
Michal Vasko8f3160e2017-09-27 11:25:26 +0200988 /* module is not yet in context, use the user callback or try to find the schema on our own */
Radek Krejci0c4a38f2018-08-28 15:50:23 +0200989 if (ctx->imp_clb && !(ctx->models.flags & LY_CTX_PREFER_SEARCHDIRS)) {
990search_clb:
991 if (ctx->imp_clb) {
992 mod = ly_ctx_load_sub_module_clb(ctx, module, name, revision, implement, unres);
Michal Vasko84475152016-07-25 16:16:25 +0200993 }
Radek Krejci0c4a38f2018-08-28 15:50:23 +0200994 if (!mod && !(ctx->models.flags & LY_CTX_PREFER_SEARCHDIRS)) {
995 goto search_file;
Michal Vasko82465962015-11-10 11:03:11 +0100996 }
Radek Krejci0c4a38f2018-08-28 15:50:23 +0200997 } else {
998search_file:
999 if (!(ctx->models.flags & LY_CTX_DISABLE_SEARCHDIRS)) {
1000 /* module was not received from the callback or there is no callback set */
1001 mod = ly_ctx_load_localfile(ctx, module, name, revision, implement, unres);
Michal Vasko84475152016-07-25 16:16:25 +02001002 }
Radek Krejci0c4a38f2018-08-28 15:50:23 +02001003 if (!mod && (ctx->models.flags & LY_CTX_PREFER_SEARCHDIRS)) {
1004 goto search_clb;
Michal Vasko82465962015-11-10 11:03:11 +01001005 }
Michal Vasko82465962015-11-10 11:03:11 +01001006 }
1007
Michal Vasko8f3160e2017-09-27 11:25:26 +02001008#ifdef LY_ENABLED_LATEST_REVISIONS
1009 if (!revision && mod) {
1010 /* module is the latest revision found */
1011 mod->latest_revision = 1;
1012 }
1013#endif
1014
Michal Vasko84475152016-07-25 16:16:25 +02001015 return mod;
1016}
1017
1018API const struct lys_module *
1019ly_ctx_load_module(struct ly_ctx *ctx, const char *name, const char *revision)
1020{
1021 if (!ctx || !name) {
Michal Vasko53b7da02018-02-13 15:28:42 +01001022 LOGARG;
Michal Vasko84475152016-07-25 16:16:25 +02001023 return NULL;
1024 }
1025
Michal Vasko53b7da02018-02-13 15:28:42 +01001026 return ly_ctx_load_sub_module(ctx, NULL, name, revision && revision[0] ? revision : NULL, 1, NULL);
Michal Vasko82465962015-11-10 11:03:11 +01001027}
1028
Radek Krejci85a54be2016-10-20 12:39:56 +02001029/*
1030 * mods - set of removed modules, if NULL all modules are supposed to be removed so any backlink is invalid
1031 */
Michal Vasko4be5fa22017-02-07 10:12:32 +01001032static void
1033ctx_modules_undo_backlinks(struct ly_ctx *ctx, struct ly_set *mods)
Radek Krejci85a54be2016-10-20 12:39:56 +02001034{
1035 int o;
1036 uint8_t j;
1037 unsigned int u, v;
1038 struct lys_module *mod;
1039 struct lys_node *elem, *next;
1040 struct lys_node_leaf *leaf;
1041
1042 /* maintain backlinks (start with internal ietf-yang-library which have leafs as possible targets of leafrefs */
Radek Krejcidfb00d62017-09-06 09:39:35 +02001043 for (o = ctx->internal_module_count - 1; o < ctx->models.used; o++) {
Radek Krejci85a54be2016-10-20 12:39:56 +02001044 mod = ctx->models.list[o]; /* shortcut */
1045
1046 /* 1) features */
1047 for (j = 0; j < mod->features_size; j++) {
1048 if (!mod->features[j].depfeatures) {
1049 continue;
1050 }
1051 for (v = 0; v < mod->features[j].depfeatures->number; v++) {
1052 if (!mods || ly_set_contains(mods, ((struct lys_feature *)mod->features[j].depfeatures->set.g[v])->module) != -1) {
1053 /* depending feature is in module to remove */
1054 ly_set_rm_index(mod->features[j].depfeatures, v);
1055 v--;
1056 }
1057 }
1058 if (!mod->features[j].depfeatures->number) {
1059 /* all backlinks removed */
1060 ly_set_free(mod->features[j].depfeatures);
1061 mod->features[j].depfeatures = NULL;
1062 }
1063 }
Michal Vasko4be5fa22017-02-07 10:12:32 +01001064
1065 /* 2) identities */
Radek Krejci85a54be2016-10-20 12:39:56 +02001066 for (u = 0; u < mod->ident_size; u++) {
1067 if (!mod->ident[u].der) {
1068 continue;
1069 }
1070 for (v = 0; v < mod->ident[u].der->number; v++) {
1071 if (!mods || ly_set_contains(mods, ((struct lys_ident *)mod->ident[u].der->set.g[v])->module) != -1) {
1072 /* derived identity is in module to remove */
1073 ly_set_rm_index(mod->ident[u].der, v);
1074 v--;
1075 }
1076 }
1077 if (!mod->ident[u].der->number) {
1078 /* all backlinks removed */
1079 ly_set_free(mod->ident[u].der);
1080 mod->ident[u].der = NULL;
1081 }
1082 }
1083
Michal Vasko4be5fa22017-02-07 10:12:32 +01001084 /* 3) leafrefs */
Radek Krejci85a54be2016-10-20 12:39:56 +02001085 for (elem = next = mod->data; elem; elem = next) {
1086 if (elem->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
1087 leaf = (struct lys_node_leaf *)elem; /* shortcut */
1088 if (leaf->backlinks) {
1089 if (!mods) {
1090 /* remove all backlinks */
1091 ly_set_free(leaf->backlinks);
1092 leaf->backlinks = NULL;
1093 } else {
1094 for (v = 0; v < leaf->backlinks->number; v++) {
1095 if (ly_set_contains(mods, leaf->backlinks->set.s[v]->module) != -1) {
1096 /* derived identity is in module to remove */
1097 ly_set_rm_index(leaf->backlinks, v);
1098 v--;
1099 }
1100 }
1101 if (!leaf->backlinks->number) {
1102 /* all backlinks removed */
1103 ly_set_free(leaf->backlinks);
1104 leaf->backlinks = NULL;
1105 }
1106 }
1107 }
1108 }
1109
1110 /* select next element to process */
1111 next = elem->child;
1112 /* child exception for leafs, leaflists, anyxml and groupings */
1113 if (elem->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA | LYS_GROUPING)) {
1114 next = NULL;
1115 }
1116 if (!next) {
1117 /* no children, try siblings */
1118 next = elem->next;
1119 }
1120 while (!next) {
1121 /* parent is already processed, go to its sibling */
1122 elem = lys_parent(elem);
1123 if (!elem) {
1124 /* we are done, no next element to process */
1125 break;
1126 }
1127 /* no siblings, go back through parents */
1128 next = elem->next;
1129 }
1130 }
1131 }
Michal Vasko4be5fa22017-02-07 10:12:32 +01001132}
Radek Krejci85a54be2016-10-20 12:39:56 +02001133
Michal Vasko4be5fa22017-02-07 10:12:32 +01001134static int
Radek Krejci83a4bac2017-02-07 15:53:04 +01001135ctx_modules_redo_backlinks(struct ly_set *mods)
Michal Vasko4be5fa22017-02-07 10:12:32 +01001136{
Radek Krejci83a4bac2017-02-07 15:53:04 +01001137 unsigned int i, j, k, s;
1138 struct lys_module *mod;
1139 struct lys_node *next, *elem;
1140 struct lys_type *type;
1141 struct lys_feature *feat;
Michal Vasko4be5fa22017-02-07 10:12:32 +01001142
Michal Vasko4be5fa22017-02-07 10:12:32 +01001143 for (i = 0; i < mods->number; ++i) {
Radek Krejci83a4bac2017-02-07 15:53:04 +01001144 mod = (struct lys_module *)mods->set.g[i]; /* shortcut */
Michal Vasko4be5fa22017-02-07 10:12:32 +01001145
Radek Krejci83a4bac2017-02-07 15:53:04 +01001146 /* identities */
Radek Krejci9e6af732017-04-27 14:40:25 +02001147 if (mod->implemented) {
1148 for (j = 0; j < mod->ident_size; j++) {
1149 for (k = 0; k < mod->ident[j].base_size; k++) {
1150 resolve_identity_backlink_update(&mod->ident[j], mod->ident[j].base[k]);
1151 }
Radek Krejci83a4bac2017-02-07 15:53:04 +01001152 }
1153 }
Michal Vasko4be5fa22017-02-07 10:12:32 +01001154
Radek Krejci83a4bac2017-02-07 15:53:04 +01001155 /* features */
1156 for (j = 0; j < mod->features_size; j++) {
1157 for (k = 0; k < mod->features[j].iffeature_size; k++) {
1158 resolve_iffeature_getsizes(&mod->features[j].iffeature[k], NULL, &s);
1159 while (s--) {
1160 feat = mod->features[j].iffeature[k].features[s]; /* shortcut */
1161 if (!feat->depfeatures) {
1162 feat->depfeatures = ly_set_new();
1163 }
1164 ly_set_add(feat->depfeatures, &mod->features[j], LY_SET_OPT_USEASLIST);
1165 }
1166 }
1167 }
1168
1169 /* leafrefs */
1170 LY_TREE_DFS_BEGIN(mod->data, next, elem) {
Michal Vaskofa3d2f72017-04-10 13:30:44 +02001171 if (elem->nodetype == LYS_GROUPING) {
1172 goto next_sibling;
1173 }
1174
Radek Krejci83a4bac2017-02-07 15:53:04 +01001175 if (elem->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
1176 type = &((struct lys_node_leaf *)elem)->type; /* shortcut */
1177 if (type->base == LY_TYPE_LEAFREF) {
1178 lys_leaf_add_leafref_target(type->info.lref.target, elem);
1179 }
1180 }
1181
Michal Vaskofa3d2f72017-04-10 13:30:44 +02001182 /* select element for the next run - children first */
1183 next = elem->child;
1184
1185 /* child exception for leafs, leaflists and anyxml without children */
1186 if (elem->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
1187 next = NULL;
1188 }
1189 if (!next) {
1190next_sibling:
1191 /* no children */
1192 if (elem == mod->data) {
1193 /* we are done, (START) has no children */
1194 break;
1195 }
1196 /* try siblings */
1197 next = elem->next;
1198 }
1199 while (!next) {
1200 /* parent is already processed, go to its sibling */
1201 elem = lys_parent(elem);
1202
1203 /* no siblings, go back through parents */
1204 if (lys_parent(elem) == lys_parent(mod->data)) {
1205 /* we are done, no next element to process */
1206 break;
1207 }
1208 next = elem->next;
1209 }
Radek Krejci83a4bac2017-02-07 15:53:04 +01001210 }
Michal Vasko4be5fa22017-02-07 10:12:32 +01001211 }
1212
1213 return 0;
Radek Krejci85a54be2016-10-20 12:39:56 +02001214}
1215
Radek Krejci8c107fe2016-10-17 16:00:18 +02001216API int
Radek Krejci0ec51da2016-12-14 16:42:03 +01001217lys_set_disabled(const struct lys_module *module)
1218{
1219 struct ly_ctx *ctx; /* shortcut */
1220 struct lys_module *mod;
1221 struct ly_set *mods;
1222 uint8_t j, imported;
1223 int i, o;
Radek Krejci29eac3d2017-06-01 16:50:02 +02001224 unsigned int u, v;
Radek Krejci0ec51da2016-12-14 16:42:03 +01001225
1226 if (!module) {
Michal Vasko53b7da02018-02-13 15:28:42 +01001227 LOGARG;
Radek Krejci0ec51da2016-12-14 16:42:03 +01001228 return EXIT_FAILURE;
1229 } else if (module->disabled) {
1230 /* already disabled module */
1231 return EXIT_SUCCESS;
1232 }
1233 mod = (struct lys_module *)module;
1234 ctx = mod->ctx;
1235
1236 /* avoid disabling internal modules */
Radek Krejcidfb00d62017-09-06 09:39:35 +02001237 for (i = 0; i < ctx->internal_module_count; i++) {
Radek Krejci0ec51da2016-12-14 16:42:03 +01001238 if (mod == ctx->models.list[i]) {
Michal Vasko53b7da02018-02-13 15:28:42 +01001239 LOGERR(ctx, LY_EINVAL, "Internal module \"%s\" cannot be disabled.", mod->name);
Radek Krejci0ec51da2016-12-14 16:42:03 +01001240 return EXIT_FAILURE;
1241 }
1242 }
1243
1244 /* disable the module */
1245 mod->disabled = 1;
1246
1247 /* get the complete list of modules to disable because of dependencies,
1248 * we are going also to disable all the imported (not implemented) modules
1249 * that are not used in any other module */
1250 mods = ly_set_new();
1251 ly_set_add(mods, mod, 0);
1252checkdependency:
Radek Krejcidfb00d62017-09-06 09:39:35 +02001253 for (i = ctx->internal_module_count; i < ctx->models.used; i++) {
Radek Krejci0ec51da2016-12-14 16:42:03 +01001254 mod = ctx->models.list[i]; /* shortcut */
1255 if (mod->disabled) {
1256 /* skip the already disabled modules */
1257 continue;
1258 }
1259
1260 /* check depndency of imported modules */
1261 for (j = 0; j < mod->imp_size; j++) {
1262 for (u = 0; u < mods->number; u++) {
1263 if (mod->imp[j].module == mods->set.g[u]) {
1264 /* module is importing some module to disable, so it must be also disabled */
1265 mod->disabled = 1;
1266 ly_set_add(mods, mod, 0);
1267 /* we have to start again because some of the already checked modules can
1268 * depend on the one we have just decided to disable */
1269 goto checkdependency;
1270 }
1271 }
1272 }
1273 /* check if the imported module is used in any module supposed to be kept */
1274 if (!mod->implemented) {
1275 imported = 0;
Radek Krejcidfb00d62017-09-06 09:39:35 +02001276 for (o = ctx->internal_module_count; o < ctx->models.used; o++) {
Radek Krejci0ec51da2016-12-14 16:42:03 +01001277 if (ctx->models.list[o]->disabled) {
1278 /* skip modules already disabled */
1279 continue;
1280 }
1281 for (j = 0; j < ctx->models.list[o]->imp_size; j++) {
1282 if (ctx->models.list[o]->imp[j].module == mod) {
1283 /* the module is used in some other module not yet selected to be disabled */
1284 imported = 1;
1285 goto imported;
1286 }
1287 }
1288 }
1289imported:
1290 if (!imported) {
1291 /* module is not implemented and neither imported by any other module in context
1292 * which is supposed to be kept enabled after this operation, so we are going to disable also
1293 * this module */
1294 mod->disabled = 1;
1295 ly_set_add(mods, mod, 0);
1296 /* we have to start again, this time not because other module can depend on this one
1297 * (we know that there is no such module), but because the module can import module
1298 * that could became useless. If there are no imports, we can continue */
1299 if (mod->imp_size) {
1300 goto checkdependency;
1301 }
1302 }
1303 }
1304 }
1305
1306 /* before removing applied deviations, augments and updating leafrefs, we have to enable the modules
1307 * to disable to allow all that operations */
1308 for (u = 0; u < mods->number; u++) {
1309 ((struct lys_module *)mods->set.g[u])->disabled = 0;
1310 }
1311
1312 /* maintain backlinks (start with internal ietf-yang-library which have leafs as possible targets of leafrefs */
Michal Vasko4be5fa22017-02-07 10:12:32 +01001313 ctx_modules_undo_backlinks(ctx, mods);
Radek Krejci0ec51da2016-12-14 16:42:03 +01001314
1315 /* remove the applied deviations and augments */
Michal Vaskoadafded2018-03-19 14:28:26 +01001316 u = mods->number;
1317 while (u--) {
Radek Krejci0ec51da2016-12-14 16:42:03 +01001318 lys_sub_module_remove_devs_augs((struct lys_module *)mods->set.g[u]);
1319 }
1320
Radek Krejci29eac3d2017-06-01 16:50:02 +02001321 /* now again disable the modules to disable and disable also all its submodules */
Radek Krejci0ec51da2016-12-14 16:42:03 +01001322 for (u = 0; u < mods->number; u++) {
Radek Krejci29eac3d2017-06-01 16:50:02 +02001323 mod = (struct lys_module *)mods->set.g[u];
1324 mod->disabled = 1;
1325 for (v = 0; v < mod->inc_size; v++) {
1326 mod->inc[v].submodule->disabled = 1;
1327 }
Radek Krejci0ec51da2016-12-14 16:42:03 +01001328 }
1329
1330 /* free the set */
1331 ly_set_free(mods);
1332
1333 /* update the module-set-id */
1334 ctx->models.module_set_id++;
1335
1336 return EXIT_SUCCESS;
1337}
1338
1339static void
1340lys_set_enabled_(struct ly_set *mods, struct lys_module *mod)
1341{
1342 unsigned int i;
1343
1344 ly_set_add(mods, mod, 0);
1345 mod->disabled = 0;
1346
Radek Krejci29eac3d2017-06-01 16:50:02 +02001347 for (i = 0; i < mod->inc_size; i++) {
1348 mod->inc[i].submodule->disabled = 0;
1349 }
1350
Radek Krejci0ec51da2016-12-14 16:42:03 +01001351 /* go recursively */
1352 for (i = 0; i < mod->imp_size; i++) {
1353 if (!mod->imp[i].module->disabled) {
1354 continue;
1355 }
1356
1357 lys_set_enabled_(mods, mod->imp[i].module);
1358 }
1359}
1360
1361API int
1362lys_set_enabled(const struct lys_module *module)
1363{
1364 struct ly_ctx *ctx; /* shortcut */
1365 struct lys_module *mod;
1366 struct ly_set *mods, *disabled;
1367 int i;
Radek Krejci29eac3d2017-06-01 16:50:02 +02001368 unsigned int u, v, w;
Radek Krejci0ec51da2016-12-14 16:42:03 +01001369
1370 if (!module) {
Michal Vasko53b7da02018-02-13 15:28:42 +01001371 LOGARG;
Radek Krejci0ec51da2016-12-14 16:42:03 +01001372 return EXIT_FAILURE;
1373 } else if (!module->disabled) {
1374 /* already enabled module */
1375 return EXIT_SUCCESS;
1376 }
1377 mod = (struct lys_module *)module;
1378 ctx = mod->ctx;
1379
1380 /* avoid disabling internal modules */
Radek Krejcidfb00d62017-09-06 09:39:35 +02001381 for (i = 0; i < ctx->internal_module_count; i++) {
Radek Krejci0ec51da2016-12-14 16:42:03 +01001382 if (mod == ctx->models.list[i]) {
Michal Vasko53b7da02018-02-13 15:28:42 +01001383 LOGERR(ctx, LY_EINVAL, "Internal module \"%s\" cannot be removed.", mod->name);
Radek Krejci0ec51da2016-12-14 16:42:03 +01001384 return EXIT_FAILURE;
1385 }
1386 }
1387
1388 mods = ly_set_new();
1389 disabled = ly_set_new();
1390
1391 /* enable the module, including its dependencies */
1392 lys_set_enabled_(mods, mod);
1393
1394 /* we will go through the all disabled modules in the context, if the module has no dependency (import)
1395 * that is still disabled AND at least one of its imported module is from the set we are enabling now,
1396 * it is going to be also enabled. This way we try to revert everething that was possibly done by
1397 * lys_set_disabled(). */
1398checkdependency:
Radek Krejcidfb00d62017-09-06 09:39:35 +02001399 for (i = ctx->internal_module_count; i < ctx->models.used; i++) {
Radek Krejci0ec51da2016-12-14 16:42:03 +01001400 mod = ctx->models.list[i]; /* shortcut */
1401 if (!mod->disabled || ly_set_contains(disabled, mod) != -1) {
1402 /* skip the enabled modules */
1403 continue;
1404 }
1405
1406 /* check imported modules */
1407 for (u = 0; u < mod->imp_size; u++) {
1408 if (mod->imp[u].module->disabled) {
1409 /* it has disabled dependency so it must stay disabled */
1410 break;
1411 }
1412 }
1413 if (u < mod->imp_size) {
1414 /* it has disabled dependency, continue with the next module in the context */
1415 continue;
1416 }
1417
1418 /* get know if at least one of the imported modules is being enabled this time */
1419 for (u = 0; u < mod->imp_size; u++) {
1420 for (v = 0; v < mods->number; v++) {
1421 if (mod->imp[u].module == mods->set.g[v]) {
1422 /* yes, it is, so they are connected and we are going to enable it as well,
1423 * it is not necessary to call recursive lys_set_enable_() because we already
1424 * know that there is no disabled import to enable */
1425 mod->disabled = 0;
1426 ly_set_add(mods, mod, 0);
Radek Krejci29eac3d2017-06-01 16:50:02 +02001427 for (w = 0; w < mod->inc_size; w++) {
1428 mod->inc[w].submodule->disabled = 0;
1429 }
Radek Krejci0ec51da2016-12-14 16:42:03 +01001430 /* we have to start again because some of the already checked modules can
1431 * depend on the one we have just decided to enable */
1432 goto checkdependency;
1433 }
1434 }
1435 }
1436
1437 /* this module is disabled, but it does not depend on any other disabled module and none
1438 * of its imports was not enabled in this call. No future enabling of the disabled module
1439 * will change this so we can remember the module and skip it next time we will have to go
1440 * through the all context because of the checkdependency goto.
1441 */
1442 ly_set_add(disabled, mod, 0);
1443 }
1444
1445 /* maintain backlinks (start with internal ietf-yang-library which have leafs as possible targets of leafrefs */
Radek Krejci83a4bac2017-02-07 15:53:04 +01001446 ctx_modules_redo_backlinks(mods);
Radek Krejci0ec51da2016-12-14 16:42:03 +01001447
1448 /* re-apply the deviations and augments */
1449 for (v = 0; v < mods->number; v++) {
Michal Vaskob87da772018-06-15 11:31:22 +02001450 if (((struct lys_module *)mods->set.g[v])->implemented) {
1451 lys_sub_module_apply_devs_augs((struct lys_module *)mods->set.g[v]);
1452 }
Radek Krejci0ec51da2016-12-14 16:42:03 +01001453 }
1454
1455 /* free the sets */
1456 ly_set_free(mods);
1457 ly_set_free(disabled);
1458
1459 /* update the module-set-id */
1460 ctx->models.module_set_id++;
1461
1462 return EXIT_SUCCESS;
1463}
1464
1465API int
1466ly_ctx_remove_module(const struct lys_module *module,
Radek Krejci8c107fe2016-10-17 16:00:18 +02001467 void (*private_destructor)(const struct lys_node *node, void *priv))
1468{
Radek Krejci0ec51da2016-12-14 16:42:03 +01001469 struct ly_ctx *ctx; /* shortcut */
Radek Krejci8c107fe2016-10-17 16:00:18 +02001470 struct lys_module *mod = NULL;
1471 struct ly_set *mods;
1472 uint8_t j, imported;
1473 int i, o;
1474 unsigned int u;
1475
Radek Krejci0ec51da2016-12-14 16:42:03 +01001476 if (!module) {
Michal Vasko53b7da02018-02-13 15:28:42 +01001477 LOGARG;
Radek Krejci8c107fe2016-10-17 16:00:18 +02001478 return EXIT_FAILURE;
1479 }
1480
Radek Krejci0ec51da2016-12-14 16:42:03 +01001481 mod = (struct lys_module *)module;
1482 ctx = mod->ctx;
1483
Radek Krejci8c107fe2016-10-17 16:00:18 +02001484 /* avoid removing internal modules ... */
Radek Krejcidfb00d62017-09-06 09:39:35 +02001485 for (i = 0; i < ctx->internal_module_count; i++) {
Radek Krejci8c107fe2016-10-17 16:00:18 +02001486 if (mod == ctx->models.list[i]) {
Michal Vasko53b7da02018-02-13 15:28:42 +01001487 LOGERR(ctx, LY_EINVAL, "Internal module \"%s\" cannot be removed.", mod->name);
Radek Krejci8c107fe2016-10-17 16:00:18 +02001488 return EXIT_FAILURE;
1489 }
1490 }
1491 /* ... and hide the module from the further processing of the context modules list */
Radek Krejcidfb00d62017-09-06 09:39:35 +02001492 for (i = ctx->internal_module_count; i < ctx->models.used; i++) {
Radek Krejci8c107fe2016-10-17 16:00:18 +02001493 if (mod == ctx->models.list[i]) {
1494 ctx->models.list[i] = NULL;
1495 break;
1496 }
1497 }
1498
1499 /* get the complete list of modules to remove because of dependencies,
1500 * we are going also to remove all the imported (not implemented) modules
1501 * that are not used in any other module */
1502 mods = ly_set_new();
1503 ly_set_add(mods, mod, 0);
1504checkdependency:
Radek Krejcidfb00d62017-09-06 09:39:35 +02001505 for (i = ctx->internal_module_count; i < ctx->models.used; i++) {
Radek Krejci8c107fe2016-10-17 16:00:18 +02001506 mod = ctx->models.list[i]; /* shortcut */
1507 if (!mod) {
1508 /* skip modules already selected for removing */
1509 continue;
1510 }
1511
1512 /* check depndency of imported modules */
1513 for (j = 0; j < mod->imp_size; j++) {
1514 for (u = 0; u < mods->number; u++) {
1515 if (mod->imp[j].module == mods->set.g[u]) {
1516 /* module is importing some module to remove, so it must be also removed */
1517 ly_set_add(mods, mod, 0);
1518 ctx->models.list[i] = NULL;
1519 /* we have to start again because some of the already checked modules can
1520 * depend on the one we have just decided to remove */
1521 goto checkdependency;
1522 }
1523 }
1524 }
1525 /* check if the imported module is used in any module supposed to be kept */
1526 if (!mod->implemented) {
1527 imported = 0;
Radek Krejcidfb00d62017-09-06 09:39:35 +02001528 for (o = ctx->internal_module_count; o < ctx->models.used; o++) {
Radek Krejci8c107fe2016-10-17 16:00:18 +02001529 if (!ctx->models.list[o]) {
1530 /* skip modules already selected for removing */
1531 continue;
1532 }
1533 for (j = 0; j < ctx->models.list[o]->imp_size; j++) {
1534 if (ctx->models.list[o]->imp[j].module == mod) {
1535 /* the module is used in some other module not yet selected to be deleted */
1536 imported = 1;
1537 goto imported;
1538 }
1539 }
1540 }
1541imported:
1542 if (!imported) {
1543 /* module is not implemented and neither imported by any other module in context
1544 * which is supposed to be kept after this operation, so we are going to remove also
1545 * this useless module */
1546 ly_set_add(mods, mod, 0);
1547 ctx->models.list[i] = NULL;
1548 /* we have to start again, this time not because other module can depend on this one
Radek Krejci0ec51da2016-12-14 16:42:03 +01001549 * (we know that there is no such module), but because the module can import module
Radek Krejci8c107fe2016-10-17 16:00:18 +02001550 * that could became useless. If there are no imports, we can continue */
1551 if (mod->imp_size) {
1552 goto checkdependency;
1553 }
1554 }
1555 }
1556 }
1557
Radek Krejci8c107fe2016-10-17 16:00:18 +02001558
1559 /* consolidate the modules list */
Radek Krejcidfb00d62017-09-06 09:39:35 +02001560 for (i = o = ctx->internal_module_count; i < ctx->models.used; i++) {
Radek Krejci8c107fe2016-10-17 16:00:18 +02001561 if (ctx->models.list[o]) {
1562 /* used cell */
1563 o++;
1564 } else {
1565 /* the current output cell is empty, move here an input cell */
1566 ctx->models.list[o] = ctx->models.list[i];
1567 ctx->models.list[i] = NULL;
1568 }
1569 }
1570 /* get the last used cell to get know the number of used */
1571 while (!ctx->models.list[o]) {
1572 o--;
1573 }
1574 ctx->models.used = o + 1;
1575 ctx->models.module_set_id++;
1576
Radek Krejci85a54be2016-10-20 12:39:56 +02001577 /* maintain backlinks (start with internal ietf-yang-library which have leafs as possible targets of leafrefs */
Michal Vasko4be5fa22017-02-07 10:12:32 +01001578 ctx_modules_undo_backlinks(ctx, mods);
Radek Krejci85a54be2016-10-20 12:39:56 +02001579
1580 /* free the modules */
1581 for (u = 0; u < mods->number; u++) {
Radek Krejcib2541a32016-12-12 16:45:57 +01001582 /* remove the applied deviations and augments */
1583 lys_sub_module_remove_devs_augs((struct lys_module *)mods->set.g[u]);
Radek Krejci85a54be2016-10-20 12:39:56 +02001584 /* remove the module */
Michal Vasko10681e82018-01-16 14:54:16 +01001585 lys_free((struct lys_module *)mods->set.g[u], private_destructor, 1, 0);
Radek Krejci85a54be2016-10-20 12:39:56 +02001586 }
1587 ly_set_free(mods);
1588
Radek Krejci8c107fe2016-10-17 16:00:18 +02001589 return EXIT_SUCCESS;
1590}
1591
Radek Krejci85a54be2016-10-20 12:39:56 +02001592API void
1593ly_ctx_clean(struct ly_ctx *ctx, void (*private_destructor)(const struct lys_node *node, void *priv))
1594{
Radek Krejci85a54be2016-10-20 12:39:56 +02001595 if (!ctx) {
1596 return;
1597 }
1598
1599 /* models list */
Radek Krejcidfb00d62017-09-06 09:39:35 +02001600 for (; ctx->models.used > ctx->internal_module_count; ctx->models.used--) {
Radek Krejcifc8411a2017-02-03 10:26:05 +01001601 /* remove the applied deviations and augments */
Radek Krejcic436a232017-02-08 14:43:11 +01001602 lys_sub_module_remove_devs_augs(ctx->models.list[ctx->models.used - 1]);
Radek Krejcifc8411a2017-02-03 10:26:05 +01001603 /* remove the module */
Michal Vasko10681e82018-01-16 14:54:16 +01001604 lys_free(ctx->models.list[ctx->models.used - 1], private_destructor, 1, 0);
Radek Krejcifc8411a2017-02-03 10:26:05 +01001605 /* clean it for safer future use */
Radek Krejcic436a232017-02-08 14:43:11 +01001606 ctx->models.list[ctx->models.used - 1] = NULL;
Radek Krejci85a54be2016-10-20 12:39:56 +02001607 }
Radek Krejci85a54be2016-10-20 12:39:56 +02001608 ctx->models.module_set_id++;
1609
Radek Krejci83a4bac2017-02-07 15:53:04 +01001610 /* maintain backlinks (actually done only with ietf-yang-library since its leafs can be target of leafref) */
Michal Vasko4be5fa22017-02-07 10:12:32 +01001611 ctx_modules_undo_backlinks(ctx, NULL);
Radek Krejci85a54be2016-10-20 12:39:56 +02001612}
1613
Michal Vaskod7957c02016-04-01 10:27:26 +02001614API const struct lys_module *
1615ly_ctx_get_module_iter(const struct ly_ctx *ctx, uint32_t *idx)
1616{
1617 if (!ctx || !idx) {
Michal Vasko53b7da02018-02-13 15:28:42 +01001618 LOGARG;
Michal Vaskod7957c02016-04-01 10:27:26 +02001619 return NULL;
1620 }
1621
Radek Krejci0ec51da2016-12-14 16:42:03 +01001622 for ( ; *idx < (unsigned)ctx->models.used; (*idx)++) {
1623 if (!ctx->models.list[(*idx)]->disabled) {
1624 return ctx->models.list[(*idx)++];
1625 }
1626 }
1627
1628 return NULL;
1629}
1630
1631API const struct lys_module *
1632ly_ctx_get_disabled_module_iter(const struct ly_ctx *ctx, uint32_t *idx)
1633{
1634 if (!ctx || !idx) {
Michal Vasko53b7da02018-02-13 15:28:42 +01001635 LOGARG;
Michal Vaskod7957c02016-04-01 10:27:26 +02001636 return NULL;
1637 }
1638
Radek Krejci0ec51da2016-12-14 16:42:03 +01001639 for ( ; *idx < (unsigned)ctx->models.used; (*idx)++) {
1640 if (ctx->models.list[(*idx)]->disabled) {
1641 return ctx->models.list[(*idx)++];
1642 }
1643 }
1644
1645 return NULL;
Michal Vaskod7957c02016-04-01 10:27:26 +02001646}
1647
Michal Vasko209a6222015-10-16 09:51:07 +02001648static int
Michal Vaskoeb3bd0e2018-01-26 11:52:11 +01001649ylib_feature(struct lyd_node *parent, struct lys_module *cur_mod, int bis)
Michal Vasko209a6222015-10-16 09:51:07 +02001650{
1651 int i, j;
Michal Vaskoeb3bd0e2018-01-26 11:52:11 +01001652 struct lyd_node *list;
Michal Vasko209a6222015-10-16 09:51:07 +02001653
1654 /* module features */
1655 for (i = 0; i < cur_mod->features_size; ++i) {
1656 if (!(cur_mod->features[i].flags & LYS_FENABLED)) {
1657 continue;
1658 }
1659
Michal Vaskoeb3bd0e2018-01-26 11:52:11 +01001660 if (bis) {
1661 if (!(list = lyd_new(parent, NULL, "feature")) || !lyd_new_leaf(list, NULL, "name", cur_mod->features[i].name)) {
1662 return EXIT_FAILURE;
1663 }
1664 } else if (!lyd_new_leaf(parent, NULL, "feature", cur_mod->features[i].name)) {
Michal Vasko209a6222015-10-16 09:51:07 +02001665 return EXIT_FAILURE;
1666 }
1667 }
1668
1669 /* submodule features */
Radek Krejcic071c542016-01-27 14:57:51 +01001670 for (i = 0; i < cur_mod->inc_size && cur_mod->inc[i].submodule; ++i) {
Michal Vasko209a6222015-10-16 09:51:07 +02001671 for (j = 0; j < cur_mod->inc[i].submodule->features_size; ++j) {
1672 if (!(cur_mod->inc[i].submodule->features[j].flags & LYS_FENABLED)) {
1673 continue;
1674 }
1675
Michal Vaskoeb3bd0e2018-01-26 11:52:11 +01001676 if (bis) {
1677 if (!(list = lyd_new(parent, NULL, "feature"))
1678 || !lyd_new_leaf(list, NULL, "name", cur_mod->inc[i].submodule->features[j].name)) {
1679 return EXIT_FAILURE;
1680 }
1681 } else if (!lyd_new_leaf(parent, NULL, "feature", cur_mod->inc[i].submodule->features[j].name)) {
Michal Vasko209a6222015-10-16 09:51:07 +02001682 return EXIT_FAILURE;
1683 }
1684 }
1685 }
1686
1687 return EXIT_SUCCESS;
1688}
1689
1690static int
Michal Vaskoeb3bd0e2018-01-26 11:52:11 +01001691ylib_deviation(struct lyd_node *parent, struct lys_module *cur_mod, int bis)
Michal Vasko97d8c6d2016-02-12 11:05:48 +01001692{
Michal Vasko89563fc2016-07-28 16:19:35 +02001693 uint32_t i = 0, j;
1694 const struct lys_module *mod;
Michal Vasko209a6222015-10-16 09:51:07 +02001695 struct lyd_node *cont;
Michal Vasko89563fc2016-07-28 16:19:35 +02001696 const char *ptr;
Michal Vasko209a6222015-10-16 09:51:07 +02001697
Michal Vasko89563fc2016-07-28 16:19:35 +02001698 if (cur_mod->deviated) {
1699 while ((mod = ly_ctx_get_module_iter(cur_mod->ctx, &i))) {
1700 if (mod == cur_mod) {
1701 continue;
Michal Vasko209a6222015-10-16 09:51:07 +02001702 }
Michal Vasko209a6222015-10-16 09:51:07 +02001703
Michal Vasko89563fc2016-07-28 16:19:35 +02001704 for (j = 0; j < mod->deviation_size; ++j) {
1705 ptr = strstr(mod->deviation[j].target_name, cur_mod->name);
1706 if (ptr && ptr[strlen(cur_mod->name)] == ':') {
1707 cont = lyd_new(parent, NULL, "deviation");
1708 if (!cont) {
1709 return EXIT_FAILURE;
1710 }
1711
Michal Vaskoeb3bd0e2018-01-26 11:52:11 +01001712 if (bis) {
1713 if (!lyd_new_leaf(cont, NULL, "module", mod->name)) {
1714 return EXIT_FAILURE;
1715 }
1716 } else {
1717 if (!lyd_new_leaf(cont, NULL, "name", mod->name)) {
1718 return EXIT_FAILURE;
1719 }
1720 if (!lyd_new_leaf(cont, NULL, "revision", (mod->rev_size ? mod->rev[0].date : ""))) {
1721 return EXIT_FAILURE;
1722 }
Michal Vasko89563fc2016-07-28 16:19:35 +02001723 }
Michal Vasko0c2215b2016-08-25 14:18:43 +02001724
1725 break;
Michal Vasko89563fc2016-07-28 16:19:35 +02001726 }
Michal Vasko209a6222015-10-16 09:51:07 +02001727 }
1728 }
1729 }
1730
1731 return EXIT_SUCCESS;
1732}
1733
1734static int
Michal Vaskoeb3bd0e2018-01-26 11:52:11 +01001735ylib_submodules(struct lyd_node *parent, struct lys_module *cur_mod, int bis)
Michal Vasko209a6222015-10-16 09:51:07 +02001736{
1737 int i;
Radek Krejcia77904e2016-02-25 16:23:45 +01001738 char *str;
Radek Krejcid9723912016-09-16 17:06:06 +02001739 struct lyd_node *item;
Michal Vasko209a6222015-10-16 09:51:07 +02001740
Radek Krejcic071c542016-01-27 14:57:51 +01001741 for (i = 0; i < cur_mod->inc_size && cur_mod->inc[i].submodule; ++i) {
Radek Krejcid9723912016-09-16 17:06:06 +02001742 item = lyd_new(parent, NULL, "submodule");
Radek Krejci6e05cea2015-12-10 16:34:37 +01001743 if (!item) {
Michal Vasko209a6222015-10-16 09:51:07 +02001744 return EXIT_FAILURE;
1745 }
1746
Radek Krejci6e05cea2015-12-10 16:34:37 +01001747 if (!lyd_new_leaf(item, NULL, "name", cur_mod->inc[i].submodule->name)) {
Michal Vasko209a6222015-10-16 09:51:07 +02001748 return EXIT_FAILURE;
1749 }
Michal Vaskoeb3bd0e2018-01-26 11:52:11 +01001750 if ((!bis || cur_mod->inc[i].submodule->rev_size)
1751 && !lyd_new_leaf(item, NULL, "revision",
1752 (cur_mod->inc[i].submodule->rev_size ? cur_mod->inc[i].submodule->rev[0].date : ""))) {
Michal Vasko209a6222015-10-16 09:51:07 +02001753 return EXIT_FAILURE;
1754 }
Radek Krejcia77904e2016-02-25 16:23:45 +01001755 if (cur_mod->inc[i].submodule->filepath) {
Radek Krejci95aa2012016-03-03 11:21:09 +01001756 if (asprintf(&str, "file://%s", cur_mod->inc[i].submodule->filepath) == -1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01001757 LOGMEM(cur_mod->ctx);
Radek Krejcia77904e2016-02-25 16:23:45 +01001758 return EXIT_FAILURE;
Michal Vaskoeb3bd0e2018-01-26 11:52:11 +01001759 } else if (!lyd_new_leaf(item, NULL, bis ? "location" : "schema", str)) {
Radek Krejci19f9ede2016-02-25 16:29:21 +01001760 free(str);
Radek Krejcia77904e2016-02-25 16:23:45 +01001761 return EXIT_FAILURE;
1762 }
Radek Krejci19f9ede2016-02-25 16:29:21 +01001763 free(str);
Michal Vasko209a6222015-10-16 09:51:07 +02001764 }
1765 }
1766
1767 return EXIT_SUCCESS;
1768}
1769
Radek Krejci14116592018-05-16 12:26:06 +02001770API uint16_t
1771ly_ctx_get_module_set_id(const struct ly_ctx *ctx)
1772{
1773 return ctx->models.module_set_id;
1774}
1775
Michal Vasko209a6222015-10-16 09:51:07 +02001776API struct lyd_node *
1777ly_ctx_info(struct ly_ctx *ctx)
1778{
Radek Krejcidfb00d62017-09-06 09:39:35 +02001779 int i, bis = 0;
Michal Vasko209a6222015-10-16 09:51:07 +02001780 char id[8];
Radek Krejcia77904e2016-02-25 16:23:45 +01001781 char *str;
Michal Vasko1e62a092015-12-01 12:27:20 +01001782 const struct lys_module *mod;
Michal Vaskoeb3bd0e2018-01-26 11:52:11 +01001783 struct lyd_node *root, *root_bis = NULL, *cont = NULL, *set_bis = NULL;
Michal Vasko209a6222015-10-16 09:51:07 +02001784
Michal Vasko7eccc6c2016-03-24 14:56:33 +01001785 if (!ctx) {
Michal Vasko53b7da02018-02-13 15:28:42 +01001786 LOGARG;
Michal Vasko7eccc6c2016-03-24 14:56:33 +01001787 return NULL;
1788 }
1789
Radek Krejcidfb00d62017-09-06 09:39:35 +02001790 mod = ly_ctx_get_module(ctx, "ietf-yang-library", NULL, 1);
Radek Krejcibd9e8d22016-02-03 14:11:48 +01001791 if (!mod || !mod->data) {
Michal Vasko53b7da02018-02-13 15:28:42 +01001792 LOGERR(ctx, LY_EINVAL, "ietf-yang-library is not implemented.");
Radek Krejcidfb00d62017-09-06 09:39:35 +02001793 return NULL;
1794 }
Michal Vaskoeb3bd0e2018-01-26 11:52:11 +01001795 if (mod->rev && !strcmp(mod->rev[0].date, "2016-04-09")) {
Radek Krejcidfb00d62017-09-06 09:39:35 +02001796 bis = 0;
1797 } else if (mod->rev && !strcmp(mod->rev[0].date, IETF_YANG_LIB_REV)) {
1798 bis = 1;
1799 } else {
Michal Vasko53b7da02018-02-13 15:28:42 +01001800 LOGERR(ctx, LY_EINVAL, "Incompatible ietf-yang-library version in context.");
Michal Vasko209a6222015-10-16 09:51:07 +02001801 return NULL;
1802 }
1803
Radek Krejcibd9e8d22016-02-03 14:11:48 +01001804 root = lyd_new(NULL, mod, "modules-state");
Michal Vasko209a6222015-10-16 09:51:07 +02001805 if (!root) {
1806 return NULL;
1807 }
1808
Radek Krejcidfb00d62017-09-06 09:39:35 +02001809 if (bis) {
Michal Vaskoeb3bd0e2018-01-26 11:52:11 +01001810 if (!(root_bis = lyd_new(NULL, mod, "yang-library")) || !(set_bis = lyd_new(root_bis, NULL, "module-set"))) {
1811 goto error;
1812 }
1813
1814 if (!lyd_new_leaf(set_bis, NULL, "name", "complete")) {
1815 goto error;
1816 }
1817
1818 sprintf(id, "%u", ctx->models.module_set_id);
1819 if (!lyd_new_leaf(set_bis, NULL, "checksum", id)) {
Radek Krejcidfb00d62017-09-06 09:39:35 +02001820 goto error;
1821 }
1822 }
1823
Michal Vasko209a6222015-10-16 09:51:07 +02001824 for (i = 0; i < ctx->models.used; ++i) {
Radek Krejci0ec51da2016-12-14 16:42:03 +01001825 if (ctx->models.list[i]->disabled) {
1826 /* skip the disabled modules */
1827 continue;
1828 }
1829
Michal Vaskoeb3bd0e2018-01-26 11:52:11 +01001830 /*
1831 * deprecated legacy
1832 */
1833 cont = lyd_new(root, NULL, "module");
Michal Vasko209a6222015-10-16 09:51:07 +02001834 if (!cont) {
Radek Krejcidfb00d62017-09-06 09:39:35 +02001835 goto error;
1836 }
Radek Krejcidfb00d62017-09-06 09:39:35 +02001837 /* name */
Michal Vaskoeb3bd0e2018-01-26 11:52:11 +01001838 if (!lyd_new_leaf(cont, NULL, "name", ctx->models.list[i]->name)) {
Radek Krejcidfb00d62017-09-06 09:39:35 +02001839 goto error;
1840 }
1841 /* revision */
Michal Vaskoeb3bd0e2018-01-26 11:52:11 +01001842 if (!lyd_new_leaf(cont, NULL, "revision", (ctx->models.list[i]->rev_size ? ctx->models.list[i]->rev[0].date : ""))) {
Radek Krejcidfb00d62017-09-06 09:39:35 +02001843 goto error;
1844 }
1845 /* schema */
Radek Krejcia77904e2016-02-25 16:23:45 +01001846 if (ctx->models.list[i]->filepath) {
Radek Krejci15412ca2016-03-03 11:16:52 +01001847 if (asprintf(&str, "file://%s", ctx->models.list[i]->filepath) == -1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01001848 LOGMEM(ctx);
Radek Krejcidfb00d62017-09-06 09:39:35 +02001849 goto error;
1850 }
Michal Vaskoeb3bd0e2018-01-26 11:52:11 +01001851 if (!lyd_new_leaf(cont, NULL, "schema", str)) {
Radek Krejcidfb00d62017-09-06 09:39:35 +02001852 free(str);
1853 goto error;
Radek Krejcia77904e2016-02-25 16:23:45 +01001854 }
Radek Krejci19f9ede2016-02-25 16:29:21 +01001855 free(str);
Michal Vasko209a6222015-10-16 09:51:07 +02001856 }
Radek Krejcidfb00d62017-09-06 09:39:35 +02001857 /* namespace */
Michal Vaskoeb3bd0e2018-01-26 11:52:11 +01001858 if (!lyd_new_leaf(cont, NULL, "namespace", ctx->models.list[i]->ns)) {
Radek Krejcidfb00d62017-09-06 09:39:35 +02001859 goto error;
1860 }
1861 /* feature leaf-list */
Michal Vaskoeb3bd0e2018-01-26 11:52:11 +01001862 if (ylib_feature(cont, ctx->models.list[i], 0)) {
Radek Krejcidfb00d62017-09-06 09:39:35 +02001863 goto error;
1864 }
1865 /* deviation list */
Michal Vaskoeb3bd0e2018-01-26 11:52:11 +01001866 if (ylib_deviation(cont, ctx->models.list[i], 0)) {
Radek Krejcidfb00d62017-09-06 09:39:35 +02001867 goto error;
Michal Vasko209a6222015-10-16 09:51:07 +02001868 }
Radek Krejcidfb00d62017-09-06 09:39:35 +02001869 /* conformance-type */
Michal Vaskoeb3bd0e2018-01-26 11:52:11 +01001870 if (!lyd_new_leaf(cont, NULL, "conformance-type", ctx->models.list[i]->implemented ? "implement" : "import")) {
Radek Krejcidfb00d62017-09-06 09:39:35 +02001871 goto error;
1872 }
1873 /* submodule list */
Michal Vaskoeb3bd0e2018-01-26 11:52:11 +01001874 if (ylib_submodules(cont, ctx->models.list[i], 0)) {
Radek Krejcidfb00d62017-09-06 09:39:35 +02001875 goto error;
1876 }
Radek Krejcidfb00d62017-09-06 09:39:35 +02001877
Michal Vaskoeb3bd0e2018-01-26 11:52:11 +01001878 /*
1879 * current revision
1880 */
1881 if (bis) {
1882 if (ctx->models.list[i]->implemented) {
1883 if (!(cont = lyd_new(set_bis, NULL, "module"))) {
1884 goto error;
1885 }
1886 } else {
1887 if (!(cont = lyd_new(set_bis, NULL, "import-only-module"))) {
1888 goto error;
1889 }
1890 }
1891 /* name */
1892 if (!lyd_new_leaf(cont, NULL, "name", ctx->models.list[i]->name)) {
Radek Krejcidfb00d62017-09-06 09:39:35 +02001893 goto error;
1894 }
Michal Vaskoeb3bd0e2018-01-26 11:52:11 +01001895 /* revision */
1896 if ((!ctx->models.list[i]->implemented || ctx->models.list[i]->rev_size)
1897 && !lyd_new_leaf(cont, NULL, "revision", ctx->models.list[i]->rev[0].date)) {
1898 goto error;
1899 }
1900 /* namespace */
1901 if (!lyd_new_leaf(cont, NULL, "namespace", ctx->models.list[i]->ns)) {
1902 goto error;
1903 }
1904 /* location */
1905 if (ctx->models.list[i]->filepath) {
1906 if (asprintf(&str, "file://%s", ctx->models.list[i]->filepath) == -1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01001907 LOGMEM(ctx);
Michal Vaskoeb3bd0e2018-01-26 11:52:11 +01001908 goto error;
1909 }
1910 if (!lyd_new_leaf(cont, NULL, "location", str)) {
1911 free(str);
1912 goto error;
1913 }
1914 free(str);
1915 }
1916 /* submodule list */
1917 if (ylib_submodules(cont, ctx->models.list[i], 1)) {
1918 goto error;
1919 }
1920 if (ctx->models.list[i]->implemented) {
1921 /* feature list */
1922 if (ylib_feature(cont, ctx->models.list[i], 1)) {
1923 goto error;
1924 }
1925 /* deviation */
1926 if (ylib_deviation(cont, ctx->models.list[i], 1)) {
1927 goto error;
1928 }
1929 }
Michal Vasko209a6222015-10-16 09:51:07 +02001930 }
1931 }
1932
1933 sprintf(id, "%u", ctx->models.module_set_id);
Michal Vaskoeb3bd0e2018-01-26 11:52:11 +01001934 if (!lyd_new_leaf(root, NULL, "module-set-id", id)) {
Radek Krejcidfb00d62017-09-06 09:39:35 +02001935 goto error;
1936 }
Michal Vaskoeb3bd0e2018-01-26 11:52:11 +01001937 if (bis && !lyd_new_leaf(root_bis, NULL, "checksum", id)) {
Radek Krejcidfb00d62017-09-06 09:39:35 +02001938 goto error;
1939 }
1940
1941 if (root_bis) {
1942 if (lyd_insert_sibling(&root_bis, root)) {
1943 goto error;
1944 }
1945 root = root_bis;
1946 root_bis = 0;
Michal Vasko209a6222015-10-16 09:51:07 +02001947 }
1948
Michal Vaskocdb90172016-09-13 09:34:36 +02001949 if (lyd_validate(&root, LYD_OPT_NOSIBLINGS, NULL)) {
Radek Krejcidfb00d62017-09-06 09:39:35 +02001950 goto error;
Michal Vasko209a6222015-10-16 09:51:07 +02001951 }
1952
1953 return root;
Radek Krejcidfb00d62017-09-06 09:39:35 +02001954
1955error:
1956 lyd_free_withsiblings(root);
1957 lyd_free_withsiblings(root_bis);
1958 return NULL;
Michal Vasko209a6222015-10-16 09:51:07 +02001959}
Michal Vaskob3744402017-08-03 14:23:58 +02001960
1961API const struct lys_node *
1962ly_ctx_get_node(struct ly_ctx *ctx, const struct lys_node *start, const char *nodeid, int output)
1963{
1964 const struct lys_node *node;
1965
Michal Vaskob3a6e482017-09-14 13:50:28 +02001966 if ((!ctx && !start) || !nodeid || ((nodeid[0] != '/') && !start)) {
Michal Vasko53b7da02018-02-13 15:28:42 +01001967 LOGARG;
Michal Vaskob3744402017-08-03 14:23:58 +02001968 return NULL;
1969 }
1970
Michal Vaskob3a6e482017-09-14 13:50:28 +02001971 if (!ctx) {
1972 ctx = start->module->ctx;
1973 }
1974
Michal Vaskob3744402017-08-03 14:23:58 +02001975 /* sets error and everything */
1976 node = resolve_json_nodeid(nodeid, ctx, start, output);
1977
1978 return node;
1979}
Radek Krejci749ebf52018-01-22 11:40:36 +01001980
Radek Krejcic683acd2018-01-22 14:51:52 +01001981API struct ly_set *
1982ly_ctx_find_path(struct ly_ctx *ctx, const char *path)
Radek Krejci749ebf52018-01-22 11:40:36 +01001983{
1984 struct ly_set *resultset = NULL;
Radek Krejci749ebf52018-01-22 11:40:36 +01001985
Radek Krejcic683acd2018-01-22 14:51:52 +01001986 if (!ctx || !path) {
Michal Vasko53b7da02018-02-13 15:28:42 +01001987 LOGARG;
Radek Krejci749ebf52018-01-22 11:40:36 +01001988 return NULL;
1989 }
1990
1991 /* start in internal module without data to make sure that all the nodes are prefixed */
Radek Krejcic683acd2018-01-22 14:51:52 +01001992 resolve_schema_nodeid(path, NULL, ctx->models.list[0], &resultset, 1, 1);
1993 return resultset;
Radek Krejci749ebf52018-01-22 11:40:36 +01001994}