blob: 38ba3e8f0eb6a2ffa879eafadaf76e79cdd5e217 [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 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
16 * distribution.
17 * 3. Neither the name of the Company nor the names of its contributors
18 * may be used to endorse or promote products derived from this
19 * software without specific prior written permission.
20 */
21
22#define _GNU_SOURCE
Radek Krejcifd4e6e32015-08-10 15:00:51 +020023#include <stddef.h>
Radek Krejcida04f4a2015-05-21 12:54:09 +020024#include <stdlib.h>
25#include <string.h>
26#include <sys/types.h>
27#include <sys/stat.h>
28#include <unistd.h>
29#include <errno.h>
30#include <fcntl.h>
31
32#include "common.h"
33#include "context.h"
34#include "dict.h"
Michal Vasko209a6222015-10-16 09:51:07 +020035#include "parser.h"
Radek Krejcibc9cf932015-07-30 11:09:39 +020036#include "tree_internal.h"
Radek Krejcida04f4a2015-05-21 12:54:09 +020037
Michal Vasko8d054e42015-08-03 12:42:06 +020038#define IETF_INET_TYPES_PATH "../models/ietf-inet-types@2013-07-15.h"
Michal Vasko21181c42015-08-03 13:46:45 +020039#define IETF_YANG_TYPES_PATH "../models/ietf-yang-types@2013-07-15.h"
Michal Vasko8d054e42015-08-03 12:42:06 +020040#define IETF_YANG_LIB_PATH "../models/ietf-yang-library@2015-07-03.h"
41
Michal Vasko8d054e42015-08-03 12:42:06 +020042#include IETF_INET_TYPES_PATH
Michal Vasko21181c42015-08-03 13:46:45 +020043#include IETF_YANG_TYPES_PATH
Michal Vasko8d054e42015-08-03 12:42:06 +020044#include IETF_YANG_LIB_PATH
45
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020046API struct ly_ctx *
47ly_ctx_new(const char *search_dir)
Radek Krejcida04f4a2015-05-21 12:54:09 +020048{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020049 struct ly_ctx *ctx;
Michal Vasko70b6d692015-08-03 14:05:59 +020050 char *cwd;
Radek Krejcida04f4a2015-05-21 12:54:09 +020051
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020052 ctx = calloc(1, sizeof *ctx);
53 if (!ctx) {
54 LOGMEM;
55 return NULL;
56 }
Radek Krejcida04f4a2015-05-21 12:54:09 +020057
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020058 /* dictionary */
59 lydict_init(&ctx->dict);
Radek Krejcida04f4a2015-05-21 12:54:09 +020060
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020061 /* models list */
62 ctx->models.list = calloc(16, sizeof *ctx->models.list);
63 ctx->models.used = 0;
64 ctx->models.size = 16;
65 if (search_dir) {
66 cwd = get_current_dir_name();
67 if (chdir(search_dir)) {
68 LOGERR(LY_ESYS, "Unable to use search directory \"%s\" (%s)",
69 search_dir, strerror(errno));
70 free(cwd);
71 ly_ctx_destroy(ctx);
72 return NULL;
73 }
74 ctx->models.search_path = get_current_dir_name();
75 chdir(cwd);
76 free(cwd);
77 }
Michal Vasko14719b22015-08-03 12:47:55 +020078 ctx->models.module_set_id = 1;
79
Michal Vasko8d054e42015-08-03 12:42:06 +020080 /* load ietf-inet-types */
81 ctx->models.list[0] = lys_parse(ctx, (char *)ietf_inet_types_2013_07_15_yin, LYS_IN_YIN);
82 if (!ctx->models.list[0]) {
83 ly_ctx_destroy(ctx);
84 return NULL;
85 }
86
87 /* load ietf-yang-types */
88 ctx->models.list[1] = lys_parse(ctx, (char *)ietf_yang_types_2013_07_15_yin, LYS_IN_YIN);
89 if (!ctx->models.list[1]) {
90 ly_ctx_destroy(ctx);
91 return NULL;
92 }
93
94 /* load ietf-yang-library */
95 ctx->models.list[2] = lys_parse(ctx, (char *)ietf_yang_library_2015_07_03_yin, LYS_IN_YIN);
96 if (!ctx->models.list[2]) {
97 ly_ctx_destroy(ctx);
98 return NULL;
99 }
Radek Krejcida04f4a2015-05-21 12:54:09 +0200100
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200101 return ctx;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200102}
103
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200104API void
Michal Vasko60ba9a62015-07-03 14:42:31 +0200105ly_ctx_set_searchdir(struct ly_ctx *ctx, const char *search_dir)
106{
107 char *cwd;
108
109 if (!ctx) {
110 return;
111 }
112
113 if (search_dir) {
114 cwd = get_current_dir_name();
115 if (chdir(search_dir)) {
116 LOGERR(LY_ESYS, "Unable to use search directory \"%s\" (%s)",
117 search_dir, strerror(errno));
118 free(cwd);
119 return;
120 }
121 ctx->models.search_path = get_current_dir_name();
122 chdir(cwd);
123 free(cwd);
124 } else {
125 free(ctx->models.search_path);
126 ctx->models.search_path = NULL;
127 }
128}
129
130API void
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200131ly_ctx_destroy(struct ly_ctx *ctx)
Radek Krejcida04f4a2015-05-21 12:54:09 +0200132{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200133 if (!ctx) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200134 return;
135 }
Radek Krejcida04f4a2015-05-21 12:54:09 +0200136
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200137 /* models list */
Radek Krejcidce51452015-06-16 15:20:08 +0200138 while (ctx->models.used) {
Michal Vasko13b15832015-08-19 11:04:48 +0200139 lys_free(ctx->models.list[0], 1);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200140 }
141 free(ctx->models.search_path);
142 free(ctx->models.list);
Radek Krejcida04f4a2015-05-21 12:54:09 +0200143
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200144 /* dictionary */
145 lydict_clean(&ctx->dict);
Radek Krejcida04f4a2015-05-21 12:54:09 +0200146
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200147 free(ctx);
Radek Krejcida04f4a2015-05-21 12:54:09 +0200148}
149
Radek Krejcib8048692015-08-05 13:36:34 +0200150API struct lys_submodule *
151ly_ctx_get_submodule(struct lys_module *module, const char *name, const char *revision)
Radek Krejciefaeba32015-05-27 14:30:57 +0200152{
Radek Krejcib8048692015-08-05 13:36:34 +0200153 struct lys_submodule *result;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200154 int i;
Radek Krejciefaeba32015-05-27 14:30:57 +0200155
Radek Krejci63a91a92015-07-29 13:31:04 +0200156 if (!module || !name) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200157 ly_errno = LY_EINVAL;
158 return NULL;
159 }
Radek Krejciefaeba32015-05-27 14:30:57 +0200160
Radek Krejcie98bb4b2015-07-30 14:21:41 +0200161 /* TODO search also for submodules not directly available from the main module */
162
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200163 /* search in modules included by the main module */
164 if (module->type) {
Radek Krejcib8048692015-08-05 13:36:34 +0200165 module = ((struct lys_submodule *)module)->belongsto;
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200166 }
167 for (i = 0; i < module->inc_size; i++) {
168 result = module->inc[i].submodule;
169 if (strcmp(name, result->name)) {
170 continue;
171 }
Radek Krejcice7fb782015-05-29 16:52:34 +0200172
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200173 if (!revision || (result->rev_size && !strcmp(revision, result->rev[0].date))) {
174 return result;
175 }
176 }
Radek Krejcice7fb782015-05-29 16:52:34 +0200177
Radek Krejci63a91a92015-07-29 13:31:04 +0200178 return NULL;
Radek Krejciefaeba32015-05-27 14:30:57 +0200179}
180
Radek Krejcifd4e6e32015-08-10 15:00:51 +0200181static struct lys_module *
182ly_ctx_get_module_by(struct ly_ctx *ctx, const char *key, int offset, const char *revision)
Radek Krejciefaeba32015-05-27 14:30:57 +0200183{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200184 int i;
Radek Krejcib8048692015-08-05 13:36:34 +0200185 struct lys_module *result = NULL;
Radek Krejciefaeba32015-05-27 14:30:57 +0200186
Radek Krejcifd4e6e32015-08-10 15:00:51 +0200187 if (!ctx || !key) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200188 ly_errno = LY_EINVAL;
189 return NULL;
190 }
Radek Krejciefaeba32015-05-27 14:30:57 +0200191
Radek Krejcidce51452015-06-16 15:20:08 +0200192 for (i = 0; i < ctx->models.used; i++) {
Radek Krejcifd4e6e32015-08-10 15:00:51 +0200193 /* use offset to get address of the pointer to string (char**), remember that offset is in
194 * bytes, so we have to cast the pointer to the module to (char*), finally, we want to have
195 * string not the pointer to string
196 */
197 if (!ctx->models.list[i] || strcmp(key, *(char**)(((char*)ctx->models.list[i]) + offset))) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200198 continue;
199 }
Radek Krejciefaeba32015-05-27 14:30:57 +0200200
Radek Krejcif647e612015-07-30 11:36:07 +0200201 if (!revision) {
202 /* compare revisons and remember the newest one */
203 if (result) {
204 if (!ctx->models.list[i]->rev_size) {
205 /* the current have no revision, keep the previous with some revision */
206 continue;
207 }
208 if (result->rev_size && strcmp(ctx->models.list[i]->rev[0].date, result->rev[0].date) < 0) {
209 /* the previous found matching module has a newer revision */
210 continue;
211 }
212 }
213
214 /* remember the current match and search for newer version */
215 result = ctx->models.list[i];
216 } else {
217 if (ctx->models.list[i]->rev_size && !strcmp(revision, ctx->models.list[i]->rev[0].date)) {
218 /* matching revision */
Michal Vasko97586502015-08-12 14:32:18 +0200219 result = ctx->models.list[i];
220 break;
Radek Krejcif647e612015-07-30 11:36:07 +0200221 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200222 }
223 }
Radek Krejciefaeba32015-05-27 14:30:57 +0200224
Radek Krejcif647e612015-07-30 11:36:07 +0200225 return result;
Radek Krejcifd4e6e32015-08-10 15:00:51 +0200226
227}
228
229API struct lys_module *
230ly_ctx_get_module_by_ns(struct ly_ctx *ctx, const char *ns, const char *revision)
231{
232 return ly_ctx_get_module_by(ctx, ns, offsetof(struct lys_module, ns), revision);
233}
234
235API struct lys_module *
236ly_ctx_get_module(struct ly_ctx *ctx, const char *name, const char *revision)
237{
238 return ly_ctx_get_module_by(ctx, name, offsetof(struct lys_module, name), revision);
Radek Krejcida04f4a2015-05-21 12:54:09 +0200239}
Michal Vasko3ec07dc2015-06-30 15:51:30 +0200240
Radek Krejci96a10da2015-07-30 11:00:14 +0200241API const char **
Michal Vasko3ec07dc2015-06-30 15:51:30 +0200242ly_ctx_get_module_names(struct ly_ctx *ctx)
243{
244 int i;
Radek Krejci96a10da2015-07-30 11:00:14 +0200245 const char **result = NULL;
Michal Vasko3ec07dc2015-06-30 15:51:30 +0200246
247 if (!ctx) {
248 ly_errno = LY_EINVAL;
249 return NULL;
250 }
251
Michal Vaskoe2ea44b2015-07-07 11:31:48 +0200252 result = malloc((ctx->models.used+1) * sizeof *result);
253
Michal Vasko3ec07dc2015-06-30 15:51:30 +0200254 for (i = 0; i < ctx->models.used; i++) {
Radek Krejci96a10da2015-07-30 11:00:14 +0200255 result[i] = ctx->models.list[i]->name;
Michal Vasko3ec07dc2015-06-30 15:51:30 +0200256 }
Michal Vaskoe2ea44b2015-07-07 11:31:48 +0200257 result[i] = NULL;
Michal Vasko3ec07dc2015-06-30 15:51:30 +0200258
259 return result;
Michal Vaskofa8c8282015-07-03 15:14:59 +0200260}
261
Radek Krejci96a10da2015-07-30 11:00:14 +0200262API const char **
263ly_ctx_get_submodule_names(struct ly_ctx *ctx, const char *module_name)
Michal Vaskofa8c8282015-07-03 15:14:59 +0200264{
265 int i;
Radek Krejci96a10da2015-07-30 11:00:14 +0200266 const char **result = NULL;
Radek Krejcib8048692015-08-05 13:36:34 +0200267 struct lys_module *mod;
Michal Vaskofa8c8282015-07-03 15:14:59 +0200268
269 if (!ctx) {
270 ly_errno = LY_EINVAL;
271 return NULL;
272 }
273
Radek Krejci96a10da2015-07-30 11:00:14 +0200274 mod = ly_ctx_get_module(ctx, module_name, NULL);
Michal Vaskofa8c8282015-07-03 15:14:59 +0200275 if (!mod) {
Radek Krejci96a10da2015-07-30 11:00:14 +0200276 LOGERR(LY_EVALID, "Data model \"%s\" not loaded", module_name);
Michal Vaskofa8c8282015-07-03 15:14:59 +0200277 return NULL;
278 }
279
280 result = malloc((mod->inc_size+1) * sizeof *result);
281
282 for (i = 0; i < mod->inc_size; i++) {
Radek Krejci96a10da2015-07-30 11:00:14 +0200283 result[i] = mod->inc[i].submodule->name;
Michal Vaskofa8c8282015-07-03 15:14:59 +0200284 }
285 result[i] = NULL;
286
287 return result;
288}
Michal Vasko209a6222015-10-16 09:51:07 +0200289
290static int
291ylib_feature(struct lyd_node *parent, struct lys_module *cur_mod)
292{
293 int i, j;
294
295 /* module features */
296 for (i = 0; i < cur_mod->features_size; ++i) {
297 if (!(cur_mod->features[i].flags & LYS_FENABLED)) {
298 continue;
299 }
300
301 if (!lyd_new_leaf_str(parent, NULL, "feature", LY_TYPE_STRING, cur_mod->features[i].name)) {
302 return EXIT_FAILURE;
303 }
304 }
305
306 /* submodule features */
307 for (i = 0; i < cur_mod->inc_size; ++i) {
308 for (j = 0; j < cur_mod->inc[i].submodule->features_size; ++j) {
309 if (!(cur_mod->inc[i].submodule->features[j].flags & LYS_FENABLED)) {
310 continue;
311 }
312
313 if (!lyd_new_leaf_str(parent, NULL, "feature", LY_TYPE_STRING, cur_mod->inc[i].submodule->features[j].name)) {
314 return EXIT_FAILURE;
315 }
316 }
317 }
318
319 return EXIT_SUCCESS;
320}
321
322static int
323ylib_deviation(struct lyd_node *parent, struct lys_module *cur_mod, struct ly_ctx *ctx)
324{
325 int i, j, k;
326 struct lys_module *target_module, *mod_iter;
327 struct lyd_node *cont;
328
329 for (i = 0; i < ctx->models.used; ++i) {
330 mod_iter = ctx->models.list[i];
331 for (k = 0; k < mod_iter->deviation_size; ++k) {
332 if (mod_iter->deviation[k].target->module->type) {
333 target_module = ((struct lys_submodule *)mod_iter->deviation[k].target->module)->belongsto;
334 } else {
335 target_module = mod_iter->deviation[k].target->module;
336 }
337
338 /* we found a module deviating our module */
339 if (target_module == cur_mod) {
340 cont = lyd_new(parent, NULL, "deviation");
341 if (!cont) {
342 return EXIT_FAILURE;
343 }
344
345 if (!lyd_new_leaf_str(cont, NULL, "name", LY_TYPE_STRING, mod_iter->name)) {
346 return EXIT_FAILURE;
347 }
348 if (!lyd_new_leaf_str(cont, NULL, "revision", LY_TYPE_STRING,
349 (mod_iter->rev_size ? mod_iter->rev[0].date : ""))) {
350 return EXIT_FAILURE;
351 }
352 }
353 }
354
355 for (j = 0; j < mod_iter->inc_size; ++j) {
356 for (k = 0; k < mod_iter->inc[j].submodule->deviation_size; ++k) {
357 if (mod_iter->inc[j].submodule->deviation[k].target->module->type) {
358 target_module = ((struct lys_submodule *)
359 mod_iter->inc[j].submodule->deviation[k].target->module)->belongsto;
360 } else {
361 target_module = mod_iter->inc[j].submodule->deviation[k].target->module;
362 }
363
364 /* we found a submodule deviating our module */
365 if (target_module == cur_mod) {
366 cont = lyd_new(parent, NULL, "deviation");
367 if (!cont) {
368 return EXIT_FAILURE;
369 }
370
371 if (!lyd_new_leaf_str(cont, NULL, "name", LY_TYPE_STRING, mod_iter->inc[j].submodule->name)) {
372 return EXIT_FAILURE;
373 }
374 if (!lyd_new_leaf_str(cont, NULL, "revision", LY_TYPE_STRING,
375 (mod_iter->inc[j].submodule->rev_size ?
376 mod_iter->inc[j].submodule->rev[0].date : ""))) {
377 return EXIT_FAILURE;
378 }
379 }
380 }
381 }
382 }
383
384 return EXIT_SUCCESS;
385}
386
387static int
388ylib_submodules(struct lyd_node *parent, struct lys_module *cur_mod)
389{
390 int i;
391 struct lyd_node *cont;
392
393 for (i = 0; i < cur_mod->inc_size; ++i) {
394 cont = lyd_new(parent, NULL, "submodule");
395 if (!cont) {
396 return EXIT_FAILURE;
397 }
398
399 if (!lyd_new_leaf_str(cont, NULL, "name", LY_TYPE_STRING, cur_mod->inc[i].submodule->name)) {
400 return EXIT_FAILURE;
401 }
402 if (!lyd_new_leaf_str(cont, NULL, "revision", LY_TYPE_STRING, (cur_mod->inc[i].submodule->rev_size ?
403 cur_mod->inc[i].submodule->rev[0].date : ""))) {
404 return EXIT_FAILURE;
405 }
406 if (cur_mod->inc[i].submodule->uri
407 && !lyd_new_leaf_str(cont, NULL, "schema", LY_TYPE_STRING, cur_mod->inc[i].submodule->uri)) {
408 return EXIT_FAILURE;
409 }
410 }
411
412 return EXIT_SUCCESS;
413}
414
415API struct lyd_node *
416ly_ctx_info(struct ly_ctx *ctx)
417{
418 int i;
419 char id[8];
420 struct lys_module *mod;
421 struct lyd_node *root, *cont;
422
423 mod = ly_ctx_get_module(ctx, "ietf-yang-library", NULL);
424 if (!mod) {
425 mod = lyp_search_file(ctx, NULL, "ietf-yang-library", NULL);
426 }
427 if (!mod || !mod->data || strcmp(mod->data->next->name, "modules")) {
428 return NULL;
429 }
430
431 root = lyd_new(NULL, mod, "modules");
432 if (!root) {
433 return NULL;
434 }
435
436 for (i = 0; i < ctx->models.used; ++i) {
437 cont = lyd_new(root, NULL, "module");
438 if (!cont) {
439 lyd_free(root);
440 return NULL;
441 }
442
443 if (!lyd_new_leaf_str(cont, NULL, "name", LY_TYPE_STRING, ctx->models.list[i]->name)) {
444 lyd_free(root);
445 return NULL;
446 }
447 if (!lyd_new_leaf_str(cont, NULL, "revision", LY_TYPE_STRING, (ctx->models.list[i]->rev_size ?
448 ctx->models.list[i]->rev[0].date : ""))) {
449 lyd_free(root);
450 return NULL;
451 }
452 if (ctx->models.list[i]->uri
453 && !lyd_new_leaf_str(cont, NULL, "schema", LY_TYPE_STRING, ctx->models.list[i]->uri)) {
454 lyd_free(root);
455 return NULL;
456 }
457 if (!lyd_new_leaf_str(cont, NULL, "namespace", LY_TYPE_STRING, ctx->models.list[i]->ns)) {
458 lyd_free(root);
459 return NULL;
460 }
461 if (ylib_feature(cont, ctx->models.list[i])) {
462 lyd_free(root);
463 return NULL;
464 }
465 if (ylib_deviation(cont, ctx->models.list[i], ctx)) {
466 lyd_free(root);
467 return NULL;
468 }
469 if (ctx->models.list[i]->implemented
470 && !lyd_new_leaf_str(cont, NULL, "conformance", LY_TYPE_ENUM, "implement")) {
471 lyd_free(root);
472 return NULL;
473 }
474 if (!ctx->models.list[i]->implemented
475 && !lyd_new_leaf_str(cont, NULL, "conformance", LY_TYPE_ENUM, "import")) {
476 lyd_free(root);
477 return NULL;
478 }
479 if (ylib_submodules(cont, ctx->models.list[i])) {
480 lyd_free(root);
481 return NULL;
482 }
483 }
484
485 sprintf(id, "%u", ctx->models.module_set_id);
486 if (!lyd_new_leaf_str(root, mod, "module-set-id", LY_TYPE_STRING, id)) {
487 lyd_free(root);
488 return NULL;
489 }
490
491 if (lyd_validate(root, 0)) {
492 lyd_free(root);
493 return NULL;
494 }
495
496 return root;
497}