blob: deff2ce70651d63f4865f3aa3e7b797323f6944d [file] [log] [blame]
Radek Krejci86d106e2018-10-18 09:53:19 +02001/**
2 * @file tree_schema_helpers.c
3 * @author Radek Krejci <rkrejci@cesnet.cz>
4 * @brief Parsing and validation helper functions
5 *
6 * Copyright (c) 2015 - 2018 CESNET, z.s.p.o.
7 *
8 * 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
11 *
12 * https://opensource.org/licenses/BSD-3-Clause
13 */
Radek Krejci9ed7a192018-10-31 16:23:51 +010014#include "common.h"
Radek Krejci86d106e2018-10-18 09:53:19 +020015
16#include <ctype.h>
Radek Krejci9ed7a192018-10-31 16:23:51 +010017#include <dirent.h>
18#include <errno.h>
19#include <fcntl.h>
Radek Krejci86d106e2018-10-18 09:53:19 +020020#include <limits.h>
Radek Krejci9ed7a192018-10-31 16:23:51 +010021#include <stdlib.h>
22#include <sys/stat.h>
23#include <sys/types.h>
24#include <unistd.h>
Radek Krejci86d106e2018-10-18 09:53:19 +020025#include <time.h>
26
27#include "libyang.h"
Radek Krejci86d106e2018-10-18 09:53:19 +020028#include "tree_schema_internal.h"
29
Radek Krejcia3045382018-11-22 14:30:31 +010030/**
31 * @brief Parse an identifier.
32 *
33 * ;; An identifier MUST NOT start with (('X'|'x') ('M'|'m') ('L'|'l'))
34 * identifier = (ALPHA / "_")
35 * *(ALPHA / DIGIT / "_" / "-" / ".")
36 *
37 * @param[in,out] id Identifier to parse. When returned, it points to the first character which is not part of the identifier.
38 * @return LY_ERR value: LY_SUCCESS or LY_EINVAL in case of invalid starting character.
39 */
40static LY_ERR
41lys_parse_id(const char **id)
42{
43 assert(id && *id);
44
45 if (!isalpha(**id) && (**id != '_')) {
46 return LY_EINVAL;
47 }
48 ++(*id);
49
50 while (isalnum(**id) || (**id == '_') || (**id == '-') || (**id == '.')) {
51 ++(*id);
52 }
53 return LY_SUCCESS;
54}
55
56LY_ERR
57lys_parse_nodeid(const char **id, const char **prefix, size_t *prefix_len, const char **name, size_t *name_len)
58{
59 assert(id && *id);
60 assert(prefix && prefix_len);
61 assert(name && name_len);
62
63 *prefix = *id;
64 *prefix_len = 0;
65 *name = NULL;
66 *name_len = 0;
67
68 LY_CHECK_RET(lys_parse_id(id));
69 if (**id == ':') {
70 /* there is prefix */
71 *prefix_len = *id - *prefix;
72 ++(*id);
73 *name = *id;
74
75 LY_CHECK_RET(lys_parse_id(id));
76 *name_len = *id - *name;
77 } else {
78 /* there is no prefix, so what we have as prefix now is actually the name */
79 *name = *prefix;
80 *name_len = *id - *name;
81 *prefix = NULL;
82 }
83
84 return LY_SUCCESS;
85}
86
Radek Krejci86d106e2018-10-18 09:53:19 +020087LY_ERR
88lysp_check_prefix(struct ly_parser_ctx *ctx, struct lysp_module *module, const char **value)
89{
90 struct lysp_import *i;
91
92 if (module->prefix && &module->prefix != value && !strcmp(module->prefix, *value)) {
93 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_REFERENCE,
94 "Prefix \"%s\" already used as module prefix.", *value);
95 return LY_EEXIST;
96 }
97 if (module->imports) {
98 LY_ARRAY_FOR(module->imports, struct lysp_import, i) {
99 if (i->prefix && &i->prefix != value && !strcmp(i->prefix, *value)) {
100 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_REFERENCE,
101 "Prefix \"%s\" already used to import \"%s\" module.", *value, i->name);
102 return LY_EEXIST;
103 }
104 }
105 }
106 return LY_SUCCESS;
107}
108
109LY_ERR
Radek Krejci4f28eda2018-11-12 11:46:16 +0100110lysc_check_status(struct lysc_ctx *ctx,
111 uint16_t flags1, void *mod1, const char *name1,
112 uint16_t flags2, void *mod2, const char *name2)
113{
114 uint16_t flg1, flg2;
115
116 flg1 = (flags1 & LYS_STATUS_MASK) ? (flags1 & LYS_STATUS_MASK) : LYS_STATUS_CURR;
117 flg2 = (flags2 & LYS_STATUS_MASK) ? (flags2 & LYS_STATUS_MASK) : LYS_STATUS_CURR;
118
119 if ((flg1 < flg2) && (mod1 == mod2)) {
120 if (ctx) {
121 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
122 "A %s definition \"%s\" is not allowed to reference %s definition \"%s\".",
123 flg1 == LYS_STATUS_CURR ? "current" : "deprecated", name1,
124 flg2 == LYS_STATUS_OBSLT ? "obsolete" : "deprecated", name2);
125 }
126 return LY_EVALID;
127 }
128
129 return LY_SUCCESS;
130}
131
132LY_ERR
Radek Krejcibbe09a92018-11-08 09:36:54 +0100133lysp_check_date(struct ly_parser_ctx *ctx, const char *date, int date_len, const char *stmt)
Radek Krejci86d106e2018-10-18 09:53:19 +0200134{
135 int i;
136 struct tm tm, tm_;
137 char *r;
138
Radek Krejcibbe09a92018-11-08 09:36:54 +0100139 LY_CHECK_ARG_RET(ctx ? ctx->ctx : NULL, date, LY_EINVAL);
140 LY_CHECK_ERR_RET(date_len != LY_REV_SIZE - 1, LOGARG(ctx ? ctx->ctx : NULL, date_len), LY_EINVAL);
Radek Krejci86d106e2018-10-18 09:53:19 +0200141
142 /* check format */
143 for (i = 0; i < date_len; i++) {
144 if (i == 4 || i == 7) {
145 if (date[i] != '-') {
146 goto error;
147 }
148 } else if (!isdigit(date[i])) {
149 goto error;
150 }
151 }
152
153 /* check content, e.g. 2018-02-31 */
154 memset(&tm, 0, sizeof tm);
155 r = strptime(date, "%Y-%m-%d", &tm);
156 if (!r || r != &date[LY_REV_SIZE - 1]) {
157 goto error;
158 }
159 memcpy(&tm_, &tm, sizeof tm);
160 mktime(&tm_); /* mktime modifies tm_ if it refers invalid date */
161 if (tm.tm_mday != tm_.tm_mday) { /* e.g 2018-02-29 -> 2018-03-01 */
162 /* checking days is enough, since other errors
163 * have been checked by strptime() */
164 goto error;
165 }
166
167 return LY_SUCCESS;
168
169error:
Radek Krejcid33273d2018-10-25 14:55:52 +0200170 if (stmt) {
Radek Krejcibbe09a92018-11-08 09:36:54 +0100171 if (ctx) {
172 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LY_VCODE_INVAL, date_len, date, stmt);
173 } else {
174 LOGVAL(NULL, LY_VLOG_NONE, NULL, LY_VCODE_INVAL, date_len, date, stmt);
175 }
Radek Krejcid33273d2018-10-25 14:55:52 +0200176 }
Radek Krejci86d106e2018-10-18 09:53:19 +0200177 return LY_EINVAL;
178}
179
180void
181lysp_sort_revisions(struct lysp_revision *revs)
182{
183 uint8_t i, r;
184 struct lysp_revision rev;
185
186 for (i = 1, r = 0; revs && i < LY_ARRAY_SIZE(revs); i++) {
Radek Krejcib7db73a2018-10-24 14:18:40 +0200187 if (strcmp(revs[i].date, revs[r].date) > 0) {
Radek Krejci86d106e2018-10-18 09:53:19 +0200188 r = i;
189 }
190 }
191
192 if (r) {
193 /* the newest revision is not on position 0, switch them */
Radek Krejci2c4e7172018-10-19 15:56:26 +0200194 memcpy(&rev, &revs[0], sizeof rev);
195 memcpy(&revs[0], &revs[r], sizeof rev);
196 memcpy(&revs[r], &rev, sizeof rev);
Radek Krejci86d106e2018-10-18 09:53:19 +0200197 }
198}
Radek Krejci151a5b72018-10-19 14:21:44 +0200199
Radek Krejcibbe09a92018-11-08 09:36:54 +0100200static const struct lysp_tpdf *
201lysp_type_match(const char *name, struct lysp_node *node)
202{
203 struct lysp_tpdf **typedefs;
204 unsigned int u;
205
206 typedefs = lysp_node_typedefs(node);
207 if (typedefs && *typedefs) {
208 LY_ARRAY_FOR(*typedefs, u) {
209 if (!strcmp(name, (*typedefs)[u].name)) {
210 /* match */
211 return &(*typedefs)[u];
212 }
213 }
214 }
215
216 return NULL;
217}
218
Radek Krejci4f28eda2018-11-12 11:46:16 +0100219static LY_DATA_TYPE
220lysp_type_str2builtin(const char *name, size_t len)
221{
222 if (len >= 4) { /* otherwise it does not match any built-in type */
223 if (name[0] == 'b') {
224 if (name[1] == 'i') {
225 if (len == 6 && !strncmp(&name[2], "nary", 4)) {
226 return LY_TYPE_BINARY;
227 } else if (len == 4 && !strncmp(&name[2], "ts", 2)) {
228 return LY_TYPE_BITS;
229 }
230 } else if (len == 7 && !strncmp(&name[1], "oolean", 6)) {
231 return LY_TYPE_BOOL;
232 }
233 } else if (name[0] == 'd') {
234 if (len == 9 && !strncmp(&name[1], "ecimal64", 8)) {
235 return LY_TYPE_DEC64;
236 }
237 } else if (name[0] == 'e') {
238 if (len == 5 && !strncmp(&name[1], "mpty", 4)) {
239 return LY_TYPE_EMPTY;
240 } else if (len == 11 && !strncmp(&name[1], "numeration", 10)) {
241 return LY_TYPE_ENUM;
242 }
243 } else if (name[0] == 'i') {
244 if (name[1] == 'n') {
245 if (len == 4 && !strncmp(&name[2], "t8", 2)) {
246 return LY_TYPE_INT8;
247 } else if (len == 5) {
248 if (!strncmp(&name[2], "t16", 3)) {
249 return LY_TYPE_INT16;
250 } else if (!strncmp(&name[2], "t32", 3)) {
251 return LY_TYPE_INT32;
252 } else if (!strncmp(&name[2], "t64", 3)) {
253 return LY_TYPE_INT64;
254 }
255 } else if (len == 19 && !strncmp(&name[2], "stance-identifier", 17)) {
256 return LY_TYPE_INST;
257 }
258 } else if (len == 11 && !strncmp(&name[1], "dentityref", 10)) {
259 return LY_TYPE_IDENT;
260 }
261 } else if (name[0] == 'l') {
262 if (len == 7 && !strncmp(&name[1], "eafref", 6)) {
263 return LY_TYPE_LEAFREF;
264 }
265 } else if (name[0] == 's') {
266 if (len == 6 && !strncmp(&name[1], "tring", 5)) {
267 return LY_TYPE_STRING;
268 }
269 } else if (name[0] == 'u') {
270 if (name[1] == 'n') {
271 if (len == 5 && !strncmp(&name[2], "ion", 3)) {
272 return LY_TYPE_UNION;
273 }
274 } else if (name[1] == 'i' && name[2] == 'n' && name[3] == 't') {
275 if (len == 5 && name[4] == '8') {
276 return LY_TYPE_UINT8;
277 } else if (len == 6) {
278 if (!strncmp(&name[4], "16", 2)) {
279 return LY_TYPE_UINT16;
280 } else if (!strncmp(&name[4], "32", 2)) {
281 return LY_TYPE_UINT32;
282 } else if (!strncmp(&name[4], "64", 2)) {
283 return LY_TYPE_UINT64;
284 }
285 }
286 }
287 }
288 }
289
290 return LY_TYPE_UNKNOWN;
291}
292
Radek Krejcibbe09a92018-11-08 09:36:54 +0100293LY_ERR
294lysp_type_find(const char *id, struct lysp_node *start_node, struct lysp_module *start_module,
Radek Krejci4f28eda2018-11-12 11:46:16 +0100295 LY_DATA_TYPE *type, const struct lysp_tpdf **tpdf, struct lysp_node **node, struct lysp_module **module)
Radek Krejcibbe09a92018-11-08 09:36:54 +0100296{
297 const char *str, *name;
298 struct lysp_tpdf *typedefs;
299 unsigned int u, v;
300
301 assert(id);
302 assert(start_module);
303 assert(tpdf);
304 assert(node);
305 assert(module);
306
Radek Krejci4f28eda2018-11-12 11:46:16 +0100307 *node = NULL;
Radek Krejcibbe09a92018-11-08 09:36:54 +0100308 str = strchr(id, ':');
309 if (str) {
310 *module = lysp_module_find_prefix(start_module, id, str - id);
311 name = str + 1;
Radek Krejci4f28eda2018-11-12 11:46:16 +0100312 *type = LY_TYPE_UNKNOWN;
Radek Krejcibbe09a92018-11-08 09:36:54 +0100313 } else {
314 *module = start_module;
315 name = id;
Radek Krejci4f28eda2018-11-12 11:46:16 +0100316
317 /* check for built-in types */
318 *type = lysp_type_str2builtin(name, strlen(name));
319 if (*type) {
320 *tpdf = NULL;
321 return LY_SUCCESS;
322 }
Radek Krejcibbe09a92018-11-08 09:36:54 +0100323 }
324 LY_CHECK_RET(!(*module), LY_ENOTFOUND);
325
326 if (start_node && *module == start_module) {
327 /* search typedefs in parent's nodes */
328 *node = start_node;
329 while (*node) {
330 *tpdf = lysp_type_match(name, *node);
331 if (*tpdf) {
332 /* match */
333 return LY_SUCCESS;
334 }
335 *node = (*node)->parent;
336 }
337 }
338
339 /* search in top-level typedefs */
340 if ((*module)->typedefs) {
341 LY_ARRAY_FOR((*module)->typedefs, u) {
342 if (!strcmp(name, (*module)->typedefs[u].name)) {
343 /* match */
344 *tpdf = &(*module)->typedefs[u];
345 return LY_SUCCESS;
346 }
347 }
348 }
349
350 /* search in submodules' typedefs */
351 LY_ARRAY_FOR((*module)->includes, u) {
352 typedefs = (*module)->includes[u].submodule->typedefs;
353 if (typedefs) {
354 LY_ARRAY_FOR(typedefs, v) {
355 if (!strcmp(name, typedefs[v].name)) {
356 /* match */
357 *tpdf = &typedefs[v];
358 return LY_SUCCESS;
359 }
360 }
361 }
362 }
363
364 return LY_ENOTFOUND;
365}
366
367/*
368 * @brief Check name of a new type to avoid name collisions.
369 *
370 * @param[in] ctx Parser context, module where the type is being defined is taken from here.
371 * @param[in] node Schema node where the type is being defined, NULL in case of a top-level typedef.
372 * @param[in] tpdf Typedef definition to check.
373 * @param[in,out] tpdfs_global Initialized hash table to store temporary data between calls. When the module's
374 * typedefs are checked, caller is supposed to free the table.
375 * @param[in,out] tpdfs_global Initialized hash table to store temporary data between calls. When the module's
376 * typedefs are checked, caller is supposed to free the table.
377 * @return LY_EEXIST in case of collision, LY_SUCCESS otherwise.
378 */
379static LY_ERR
380lysp_check_typedef(struct ly_parser_ctx *ctx, struct lysp_node *node, struct lysp_tpdf *tpdf,
381 struct hash_table *tpdfs_global, struct hash_table *tpdfs_scoped)
382{
383 struct lysp_node *parent;
384 uint32_t hash;
385 size_t name_len;
386 const char *name;
387 unsigned int u;
388 struct lysp_tpdf **typedefs;
389
390 assert(ctx);
391 assert(tpdf);
392
393 name = tpdf->name;
394 name_len = strlen(name);
395
Radek Krejci4f28eda2018-11-12 11:46:16 +0100396 if (lysp_type_str2builtin(name, name_len)) {
397 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_SYNTAX_YANG,
398 "Invalid name \"%s\" of typedef - name collision with a built-in type.", name);
399 return LY_EEXIST;
Radek Krejcibbe09a92018-11-08 09:36:54 +0100400 }
401
402 /* check locally scoped typedefs (avoid name shadowing) */
403 if (node) {
404 typedefs = lysp_node_typedefs(node);
405 if (typedefs && *typedefs) {
406 LY_ARRAY_FOR(*typedefs, u) {
407 if (typedefs[u] == tpdf) {
408 break;
409 }
410 if (!strcmp(name, (*typedefs)[u].name)) {
411 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_SYNTAX_YANG,
412 "Invalid name \"%s\" of typedef - name collision with sibling type.", name);
413 return LY_EEXIST;
414 }
415 }
416 }
417 /* search typedefs in parent's nodes */
418 for (parent = node->parent; parent; parent = node->parent) {
419 if (lysp_type_match(name, parent)) {
420 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_SYNTAX_YANG,
421 "Invalid name \"%s\" of typedef - name collision with another scoped type.", name);
422 return LY_EEXIST;
423 }
424 }
425 }
426
427 /* check collision with the top-level typedefs */
428 hash = dict_hash(name, name_len);
429 if (node) {
430 lyht_insert(tpdfs_scoped, &name, hash, NULL);
431 if (!lyht_find(tpdfs_global, &name, hash, NULL)) {
432 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_SYNTAX_YANG,
433 "Invalid name \"%s\" of typedef - scoped type collide with a top-level type.", name);
434 return LY_EEXIST;
435 }
436 } else {
437 if (lyht_insert(tpdfs_global, &name, hash, NULL)) {
438 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_SYNTAX_YANG,
439 "Invalid name \"%s\" of typedef - name collision with another top-level type.", name);
440 return LY_EEXIST;
441 }
Radek Krejci3b1f9292018-11-08 10:58:35 +0100442 /* it is not necessary to test collision with the scoped types - in lysp_check_typedefs, all the
443 * top-level typedefs are inserted into the tables before the scoped typedefs, so the collision
444 * is detected in the first branch few lines above */
Radek Krejcibbe09a92018-11-08 09:36:54 +0100445 }
446
447 return LY_SUCCESS;
448}
449
450static int
451lysp_id_cmp(void *val1, void *val2, int UNUSED(mod), void *UNUSED(cb_data))
452{
453 return !strcmp(val1, val2);
454}
455
456LY_ERR
457lysp_check_typedefs(struct ly_parser_ctx *ctx)
458{
459 struct hash_table *ids_global;
460 struct hash_table *ids_scoped;
461 struct lysp_tpdf **typedefs;
462 unsigned int i, u;
463 LY_ERR ret = LY_EVALID;
464
465 /* check name collisions - typedefs and groupings */
466 ids_global = lyht_new(8, sizeof(char*), lysp_id_cmp, NULL, 1);
467 ids_scoped = lyht_new(8, sizeof(char*), lysp_id_cmp, NULL, 1);
468 LY_ARRAY_FOR(ctx->mod->typedefs, i) {
469 if (lysp_check_typedef(ctx, NULL, &ctx->mod->typedefs[i], ids_global, ids_scoped)) {
470 goto cleanup;
471 }
472 }
Radek Krejci3b1f9292018-11-08 10:58:35 +0100473 LY_ARRAY_FOR(ctx->mod->includes, i) {
474 LY_ARRAY_FOR(ctx->mod->includes[i].submodule->typedefs, u) {
475 if (lysp_check_typedef(ctx, NULL, &ctx->mod->includes[i].submodule->typedefs[u], ids_global, ids_scoped)) {
476 goto cleanup;
477 }
478 }
479 }
Radek Krejcibbe09a92018-11-08 09:36:54 +0100480 for (u = 0; u < ctx->tpdfs_nodes.count; ++u) {
481 typedefs = lysp_node_typedefs((struct lysp_node *)ctx->tpdfs_nodes.objs[u]);
482 LY_ARRAY_FOR(*typedefs, i) {
483 if (lysp_check_typedef(ctx, (struct lysp_node *)ctx->tpdfs_nodes.objs[u], &(*typedefs)[i], ids_global, ids_scoped)) {
484 goto cleanup;
485 }
486 }
487 }
488 ret = LY_SUCCESS;
489cleanup:
490 lyht_free(ids_global);
491 lyht_free(ids_scoped);
492 ly_set_erase(&ctx->tpdfs_nodes, NULL);
493
494 return ret;
495}
496
Radek Krejci086c7132018-10-26 15:29:04 +0200497void
498lys_module_implement(struct lys_module *mod)
499{
500 assert(mod);
501 if (mod->parsed) {
502 mod->parsed->implemented = 1;
503 }
504 if (mod->compiled) {
505 mod->compiled->implemented = 1;
506 }
507}
508
Radek Krejci9ed7a192018-10-31 16:23:51 +0100509struct lysp_load_module_check_data {
510 const char *name;
511 const char *revision;
512 const char *path;
513 const char* submoduleof;
514};
515
516static LY_ERR
517lysp_load_module_check(struct ly_ctx *ctx, struct lysp_module *mod, void *data)
518{
519 struct lysp_load_module_check_data *info = data;
520 const char *filename, *dot, *rev;
521 size_t len;
522
523 if (info->name) {
524 /* check name of the parsed model */
525 if (strcmp(info->name, mod->name)) {
526 LOGERR(ctx, LY_EINVAL, "Unexpected module \"%s\" parsed instead of \"%s\").", mod->name, info->name);
527 return LY_EINVAL;
528 }
529 }
530 if (info->revision) {
531 /* check revision of the parsed model */
532 if (!mod->revs || strcmp(info->revision, mod->revs[0].date)) {
533 LOGERR(ctx, LY_EINVAL, "Module \"%s\" parsed with the wrong revision (\"%s\" instead \"%s\").", mod->name,
534 mod->revs[0].date, info->revision);
535 return LY_EINVAL;
536 }
537 }
538 if (info->submoduleof) {
539 /* check that we have really a submodule */
540 if (!mod->submodule) {
541 /* submodule is not a submodule */
542 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE, "Included \"%s\" schema from \"%s\" is actually not a submodule.",
543 mod->name, info->submoduleof);
544 return LY_EVALID;
545 }
546 /* check that the submodule belongs-to our module */
547 if (strcmp(info->submoduleof, mod->belongsto)) {
548 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE, "Included \"%s\" submodule from \"%s\" belongs-to a different module \"%s\".",
549 mod->name, info->submoduleof, mod->belongsto);
550 return LY_EVALID;
551 }
552 /* check circular dependency */
553 if (mod->parsing) {
554 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE, "A circular dependency (include) for module \"%s\".", mod->name);
555 return LY_EVALID;
556 }
557 }
558 if (info->path) {
559 /* check that name and revision match filename */
560 filename = strrchr(info->path, '/');
561 if (!filename) {
562 filename = info->path;
563 } else {
564 filename++;
565 }
566 /* name */
567 len = strlen(mod->name);
568 rev = strchr(filename, '@');
569 dot = strrchr(info->path, '.');
570 if (strncmp(filename, mod->name, len) ||
571 ((rev && rev != &filename[len]) || (!rev && dot != &filename[len]))) {
572 LOGWRN(ctx, "File name \"%s\" does not match module name \"%s\".", filename, mod->name);
573 }
574 /* revision */
575 if (rev) {
576 len = dot - ++rev;
577 if (!mod->revs || len != 10 || strncmp(mod->revs[0].date, rev, len)) {
578 LOGWRN(ctx, "File name \"%s\" does not match module revision \"%s\".", filename,
579 mod->revs ? mod->revs[0].date : "none");
580 }
581 }
582 }
583 return LY_SUCCESS;
584}
585
586LY_ERR
Radek Krejci3b1f9292018-11-08 10:58:35 +0100587lys_module_localfile(struct ly_ctx *ctx, const char *name, const char *revision, int implement, struct ly_parser_ctx *main_ctx,
Radek Krejci9ed7a192018-10-31 16:23:51 +0100588 struct lys_module **result)
589{
590 int fd;
591 char *filepath = NULL;
592 LYS_INFORMAT format;
593 struct lys_module *mod = NULL;
594 LY_ERR ret = LY_SUCCESS;
595 struct lysp_load_module_check_data check_data = {0};
596
597 LY_CHECK_RET(lys_search_localfile(ly_ctx_get_searchdirs(ctx), !(ctx->flags & LY_CTX_DISABLE_SEARCHDIR_CWD), name, revision,
598 &filepath, &format));
599 LY_CHECK_ERR_RET(!filepath, LOGERR(ctx, LY_ENOTFOUND, "Data model \"%s%s%s\" not found in local searchdirs.",
600 name, revision ? "@" : "", revision ? revision : ""), LY_ENOTFOUND);
601
602
603 LOGVRB("Loading schema from \"%s\" file.", filepath);
604
605 /* open the file */
606 fd = open(filepath, O_RDONLY);
607 LY_CHECK_ERR_GOTO(fd < 0, LOGERR(ctx, LY_ESYS, "Unable to open data model file \"%s\" (%s).",
608 filepath, strerror(errno)); ret = LY_ESYS, cleanup);
609
610 check_data.name = name;
611 check_data.revision = revision;
612 check_data.path = filepath;
Radek Krejci3b1f9292018-11-08 10:58:35 +0100613 mod = lys_parse_fd_(ctx, fd, format, implement, main_ctx,
Radek Krejci9ed7a192018-10-31 16:23:51 +0100614 lysp_load_module_check, &check_data);
615 close(fd);
616 LY_CHECK_ERR_GOTO(!mod, ly_errcode(ctx), cleanup);
617
618 if (!mod->parsed->filepath) {
Radek Krejci7802bae2018-11-26 15:34:10 +0100619#ifdef __APPLE__
620 char rpath[MAXPATHLEN];
621#else
Radek Krejci9ed7a192018-10-31 16:23:51 +0100622 char rpath[PATH_MAX];
Radek Krejci7802bae2018-11-26 15:34:10 +0100623#endif
Radek Krejci9ed7a192018-10-31 16:23:51 +0100624 if (realpath(filepath, rpath) != NULL) {
625 mod->parsed->filepath = lydict_insert(ctx, rpath, 0);
626 } else {
627 mod->parsed->filepath = lydict_insert(ctx, filepath, 0);
628 }
629 }
630
631 *result = mod;
632
633 /* success */
634cleanup:
635 free(filepath);
636 return ret;
637}
638
Radek Krejcid33273d2018-10-25 14:55:52 +0200639LY_ERR
Radek Krejci6d6e4e42018-10-29 13:28:19 +0100640lysp_load_module(struct ly_ctx *ctx, const char *name, const char *revision, int implement, int require_parsed, struct lys_module **mod)
Radek Krejci086c7132018-10-26 15:29:04 +0200641{
Radek Krejci9ed7a192018-10-31 16:23:51 +0100642 const char *module_data = NULL;
Radek Krejci086c7132018-10-26 15:29:04 +0200643 LYS_INFORMAT format = LYS_IN_UNKNOWN;
Radek Krejci9ed7a192018-10-31 16:23:51 +0100644 void (*module_data_free)(void *module_data, void *user_data) = NULL;
645 struct lysp_load_module_check_data check_data = {0};
Radek Krejci086c7132018-10-26 15:29:04 +0200646
647 /* try to get the module from the context */
648 if (revision) {
649 *mod = (struct lys_module*)ly_ctx_get_module(ctx, name, revision);
650 } else {
651 *mod = (struct lys_module*)ly_ctx_get_module_latest(ctx, name);
652 }
653
Radek Krejci6d6e4e42018-10-29 13:28:19 +0100654 if (!(*mod) || (require_parsed && !(*mod)->parsed)) {
655 (*mod) = NULL;
656
Radek Krejci086c7132018-10-26 15:29:04 +0200657 /* check collision with other implemented revision */
658 if (implement && ly_ctx_get_module_implemented(ctx, name)) {
659 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE,
660 "Module \"%s\" is already present in other implemented revision.", name);
661 return LY_EDENIED;
662 }
663
Radek Krejci9ed7a192018-10-31 16:23:51 +0100664 /* module not present in the context, get the input data and parse it */
Radek Krejci086c7132018-10-26 15:29:04 +0200665 if (!(ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
666search_clb:
667 if (ctx->imp_clb) {
668 if (ctx->imp_clb(name, revision, NULL, NULL, ctx->imp_clb_data,
Radek Krejci9ed7a192018-10-31 16:23:51 +0100669 &format, &module_data, &module_data_free) == LY_SUCCESS) {
670 check_data.name = name;
671 check_data.revision = revision;
Radek Krejci3b1f9292018-11-08 10:58:35 +0100672 *mod = lys_parse_mem_(ctx, module_data, format, implement, NULL,
Radek Krejci9ed7a192018-10-31 16:23:51 +0100673 lysp_load_module_check, &check_data);
674 if (module_data_free) {
675 module_data_free((void*)module_data, ctx->imp_clb_data);
676 }
Radek Krejci086c7132018-10-26 15:29:04 +0200677 }
678 }
679 if (!(*mod) && !(ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
680 goto search_file;
681 }
682 } else {
683search_file:
684 if (!(ctx->flags & LY_CTX_DISABLE_SEARCHDIRS)) {
685 /* module was not received from the callback or there is no callback set */
Radek Krejci3b1f9292018-11-08 10:58:35 +0100686 lys_module_localfile(ctx, name, revision, implement, NULL, mod);
Radek Krejci086c7132018-10-26 15:29:04 +0200687 }
688 if (!(*mod) && (ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
689 goto search_clb;
690 }
691 }
Radek Krejci9ed7a192018-10-31 16:23:51 +0100692
Radek Krejcid14e9692018-11-01 11:00:37 +0100693 if ((*mod) && !revision && ((*mod)->parsed->latest_revision == 1)) {
Radek Krejci9ed7a192018-10-31 16:23:51 +0100694 /* update the latest_revision flag - here we have selected the latest available schema,
695 * consider that even the callback provides correct latest revision */
696 (*mod)->parsed->latest_revision = 2;
697 }
Radek Krejci086c7132018-10-26 15:29:04 +0200698 } else {
699 /* we have module from the current context */
700 if (implement && (ly_ctx_get_module_implemented(ctx, name) != *mod)) {
701 /* check collision with other implemented revision */
702 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE,
703 "Module \"%s\" is already present in other implemented revision.", name);
704 *mod = NULL;
705 return LY_EDENIED;
706 }
707
708 /* circular check */
Radek Krejcif8f882a2018-10-31 14:51:15 +0100709 if ((*mod)->parsed && (*mod)->parsed->parsing) {
Radek Krejci086c7132018-10-26 15:29:04 +0200710 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE, "A circular dependency (import) for module \"%s\".", name);
711 *mod = NULL;
712 return LY_EVALID;
713 }
714 }
715 if (!(*mod)) {
Radek Krejci9ed7a192018-10-31 16:23:51 +0100716 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE, "%s \"%s\" module failed.", implement ? "Loading" : "Importing", name);
Radek Krejci086c7132018-10-26 15:29:04 +0200717 return LY_EVALID;
718 }
719
720 if (implement) {
721 /* mark the module implemented, check for collision was already done */
722 lys_module_implement(*mod);
723 }
Radek Krejci086c7132018-10-26 15:29:04 +0200724
725 return LY_SUCCESS;
726}
727
728LY_ERR
Radek Krejci3b1f9292018-11-08 10:58:35 +0100729lysp_load_submodule(struct ly_parser_ctx *ctx, struct lysp_module *mod, struct lysp_include *inc)
Radek Krejcid33273d2018-10-25 14:55:52 +0200730{
731 struct lys_module *submod;
732 const char *submodule_data = NULL;
733 LYS_INFORMAT format = LYS_IN_UNKNOWN;
734 void (*submodule_data_free)(void *module_data, void *user_data) = NULL;
Radek Krejci9ed7a192018-10-31 16:23:51 +0100735 struct lysp_load_module_check_data check_data = {0};
Radek Krejcid33273d2018-10-25 14:55:52 +0200736
Radek Krejcibbe09a92018-11-08 09:36:54 +0100737 /* submodule not present in the context, get the input data and parse it */
Radek Krejci3b1f9292018-11-08 10:58:35 +0100738 if (!(ctx->ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
Radek Krejcid33273d2018-10-25 14:55:52 +0200739search_clb:
Radek Krejci3b1f9292018-11-08 10:58:35 +0100740 if (ctx->ctx->imp_clb) {
741 if (ctx->ctx->imp_clb(mod->name, NULL, inc->name, inc->rev[0] ? inc->rev : NULL, ctx->ctx->imp_clb_data,
Radek Krejcibbe09a92018-11-08 09:36:54 +0100742 &format, &submodule_data, &submodule_data_free) == LY_SUCCESS) {
743 check_data.name = inc->name;
744 check_data.revision = inc->rev[0] ? inc->rev : NULL;
745 check_data.submoduleof = mod->name;
Radek Krejci3b1f9292018-11-08 10:58:35 +0100746 submod = lys_parse_mem_(ctx->ctx, submodule_data, format, mod->implemented, ctx,
Radek Krejcibbe09a92018-11-08 09:36:54 +0100747 lysp_load_module_check, &check_data);
748 if (submodule_data_free) {
Radek Krejci3b1f9292018-11-08 10:58:35 +0100749 submodule_data_free((void*)submodule_data, ctx->ctx->imp_clb_data);
Radek Krejcid33273d2018-10-25 14:55:52 +0200750 }
751 }
Radek Krejcid33273d2018-10-25 14:55:52 +0200752 }
Radek Krejci3b1f9292018-11-08 10:58:35 +0100753 if (!submod && !(ctx->ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
Radek Krejcibbe09a92018-11-08 09:36:54 +0100754 goto search_file;
Radek Krejcid33273d2018-10-25 14:55:52 +0200755 }
Radek Krejci2d31ea72018-10-25 15:46:42 +0200756 } else {
Radek Krejcibbe09a92018-11-08 09:36:54 +0100757search_file:
Radek Krejci3b1f9292018-11-08 10:58:35 +0100758 if (!(ctx->ctx->flags & LY_CTX_DISABLE_SEARCHDIRS)) {
Radek Krejcibbe09a92018-11-08 09:36:54 +0100759 /* module was not received from the callback or there is no callback set */
Radek Krejci3b1f9292018-11-08 10:58:35 +0100760 lys_module_localfile(ctx->ctx, inc->name, inc->rev[0] ? inc->rev : NULL, mod->implemented, ctx, &submod);
Radek Krejcibbe09a92018-11-08 09:36:54 +0100761 }
Radek Krejci3b1f9292018-11-08 10:58:35 +0100762 if (!submod && (ctx->ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
Radek Krejcibbe09a92018-11-08 09:36:54 +0100763 goto search_clb;
764 }
765 }
766 if (submod) {
767 if (!inc->rev[0] && (submod->parsed->latest_revision == 1)) {
768 /* update the latest_revision flag - here we have selected the latest available schema,
769 * consider that even the callback provides correct latest revision */
770 submod->parsed->latest_revision = 2;
771 }
772
773 inc->submodule = submod->parsed;
774 free(submod);
Radek Krejcid33273d2018-10-25 14:55:52 +0200775 }
776 if (!inc->submodule) {
Radek Krejci3b1f9292018-11-08 10:58:35 +0100777 LOGVAL(ctx->ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE, "Including \"%s\" submodule into \"%s\" failed.", inc->name, mod->name);
Radek Krejcid33273d2018-10-25 14:55:52 +0200778 return LY_EVALID;
779 }
780
781 return LY_SUCCESS;
782}
783
Radek Krejcibbe09a92018-11-08 09:36:54 +0100784#define FIND_MODULE(TYPE, MOD, ID) \
Radek Krejcice8c1592018-10-29 15:35:51 +0100785 TYPE *imp; \
786 if (!strncmp((MOD)->prefix, prefix, len) && (MOD)->prefix[len] == '\0') { \
787 /* it is the prefix of the module itself */ \
Radek Krejcibbe09a92018-11-08 09:36:54 +0100788 m = ly_ctx_get_module((MOD)->ctx, (MOD)->name, ((struct lysc_module*)(MOD))->revision); \
Radek Krejcice8c1592018-10-29 15:35:51 +0100789 } \
790 /* search in imports */ \
Radek Krejcibbe09a92018-11-08 09:36:54 +0100791 if (!m) { \
792 LY_ARRAY_FOR((MOD)->imports, TYPE, imp) { \
793 if (!strncmp(imp->prefix, prefix, len) && (MOD)->prefix[len] == '\0') { \
794 m = imp->module; \
795 break; \
796 } \
Radek Krejcice8c1592018-10-29 15:35:51 +0100797 } \
Radek Krejcibbe09a92018-11-08 09:36:54 +0100798 }
Radek Krejcice8c1592018-10-29 15:35:51 +0100799
Radek Krejcibbe09a92018-11-08 09:36:54 +0100800struct lysc_module *
Radek Krejcia3045382018-11-22 14:30:31 +0100801lysc_module_find_prefix(const struct lysc_module *mod, const char *prefix, size_t len)
Radek Krejci151a5b72018-10-19 14:21:44 +0200802{
Radek Krejcibbe09a92018-11-08 09:36:54 +0100803 const struct lys_module *m = NULL;
804
805 FIND_MODULE(struct lysc_import, mod, 1);
806 return m ? m->compiled : NULL;
Radek Krejcice8c1592018-10-29 15:35:51 +0100807}
Radek Krejci151a5b72018-10-19 14:21:44 +0200808
Radek Krejcibbe09a92018-11-08 09:36:54 +0100809struct lysp_module *
Radek Krejcia3045382018-11-22 14:30:31 +0100810lysp_module_find_prefix(const struct lysp_module *mod, const char *prefix, size_t len)
Radek Krejcice8c1592018-10-29 15:35:51 +0100811{
Radek Krejcibbe09a92018-11-08 09:36:54 +0100812 const struct lys_module *m = NULL;
813
814 FIND_MODULE(struct lysp_import, mod, 1);
815 return m ? m->parsed : NULL;
Radek Krejcice8c1592018-10-29 15:35:51 +0100816}
Radek Krejci151a5b72018-10-19 14:21:44 +0200817
Radek Krejcice8c1592018-10-29 15:35:51 +0100818struct lys_module *
Radek Krejcia3045382018-11-22 14:30:31 +0100819lys_module_find_prefix(const struct lys_module *mod, const char *prefix, size_t len)
Radek Krejcice8c1592018-10-29 15:35:51 +0100820{
Radek Krejcibbe09a92018-11-08 09:36:54 +0100821 const struct lys_module *m = NULL;
822
Radek Krejcice8c1592018-10-29 15:35:51 +0100823 if (mod->compiled) {
Radek Krejcibbe09a92018-11-08 09:36:54 +0100824 FIND_MODULE(struct lysc_import, mod->compiled, 1);
Radek Krejcice8c1592018-10-29 15:35:51 +0100825 } else {
Radek Krejcibbe09a92018-11-08 09:36:54 +0100826 FIND_MODULE(struct lysp_import, mod->parsed, 2);
827 }
828 return (struct lys_module*)m;
829}
830
Radek Krejcia3045382018-11-22 14:30:31 +0100831const char *
832lys_nodetype2str(uint16_t nodetype)
833{
834 switch(nodetype) {
835 case LYS_CONTAINER:
836 return "container";
837 case LYS_CHOICE:
838 return "choice";
839 case LYS_LEAF:
840 return "leaf";
841 case LYS_LEAFLIST:
842 return "leaf-list";
843 case LYS_LIST:
844 return "list";
845 case LYS_ANYXML:
846 return "anyxml";
847 case LYS_ANYDATA:
848 return "anydata";
849 default:
850 return "unknown";
851 }
852}
853
Radek Krejcibbe09a92018-11-08 09:36:54 +0100854struct lysp_tpdf **
855lysp_node_typedefs(struct lysp_node *node)
856{
857 switch (node->nodetype) {
858 case LYS_CONTAINER:
859 return &((struct lysp_node_container*)node)->typedefs;
860 case LYS_LIST:
861 return &((struct lysp_node_list*)node)->typedefs;
862 case LYS_GROUPING:
863 return &((struct lysp_grp*)node)->typedefs;
864 case LYS_ACTION:
865 return &((struct lysp_action*)node)->typedefs;
866 case LYS_INOUT:
867 return &((struct lysp_action_inout*)node)->typedefs;
868 case LYS_NOTIF:
869 return &((struct lysp_notif*)node)->typedefs;
870 default:
871 return NULL;
Radek Krejci151a5b72018-10-19 14:21:44 +0200872 }
Radek Krejci151a5b72018-10-19 14:21:44 +0200873}
Radek Krejcibbe09a92018-11-08 09:36:54 +0100874
875struct lysp_action **
876lysp_node_actions(struct lysp_node *node)
877{
878 assert(node);
879 switch (node->nodetype) {
880 case LYS_CONTAINER:
881 return &((struct lysp_node_container*)node)->actions;
882 case LYS_LIST:
883 return &((struct lysp_node_list*)node)->actions;
884 case LYS_GROUPING:
885 return &((struct lysp_grp*)node)->actions;
886 case LYS_AUGMENT:
887 return &((struct lysp_augment*)node)->actions;
888 default:
889 return NULL;
890 }
891}
892
893struct lysp_notif **
894lysp_node_notifs(struct lysp_node *node)
895{
896 assert(node);
897 switch (node->nodetype) {
898 case LYS_CONTAINER:
899 return &((struct lysp_node_container*)node)->notifs;
900 case LYS_LIST:
901 return &((struct lysp_node_list*)node)->notifs;
902 case LYS_GROUPING:
903 return &((struct lysp_grp*)node)->notifs;
904 case LYS_AUGMENT:
905 return &((struct lysp_augment*)node)->notifs;
906 default:
907 return NULL;
908 }
909}
910
911struct lysp_node **
912lysp_node_children(struct lysp_node *node)
913{
914 assert(node);
915 switch (node->nodetype) {
916 case LYS_CONTAINER:
917 return &((struct lysp_node_container*)node)->child;
918 case LYS_CHOICE:
919 return &((struct lysp_node_choice*)node)->child;
920 case LYS_LIST:
921 return &((struct lysp_node_list*)node)->child;
922 case LYS_CASE:
923 return &((struct lysp_node_case*)node)->child;
924 case LYS_GROUPING:
925 return &((struct lysp_grp*)node)->data;
926 case LYS_AUGMENT:
927 return &((struct lysp_augment*)node)->child;
928 case LYS_INOUT:
929 return &((struct lysp_action_inout*)node)->data;
930 case LYS_NOTIF:
931 return &((struct lysp_notif*)node)->data;
932 default:
933 return NULL;
934 }
935}
936
937struct lysc_node **
Radek Krejcia3045382018-11-22 14:30:31 +0100938lysc_node_children(const struct lysc_node *node)
Radek Krejcibbe09a92018-11-08 09:36:54 +0100939{
940 assert(node);
941 switch (node->nodetype) {
942 case LYS_CONTAINER:
943 return &((struct lysc_node_container*)node)->child;
944 case LYS_CHOICE:
Radek Krejcia3045382018-11-22 14:30:31 +0100945 if (((struct lysc_node_choice*)node)->cases) {
946 return &((struct lysc_node_choice*)node)->cases[0].child;
947 } else {
948 return NULL;
949 }
Radek Krejcibbe09a92018-11-08 09:36:54 +0100950 case LYS_LIST:
951 return &((struct lysc_node_list*)node)->child;
Radek Krejcibbe09a92018-11-08 09:36:54 +0100952/* TODO
953 case LYS_INOUT:
954 return &((struct lysc_action_inout*)node)->child;
955 case LYS_NOTIF:
956 return &((struct lysc_notif*)node)->child;
957*/
958 default:
959 return NULL;
960 }
961}
962
Radek Krejcia3045382018-11-22 14:30:31 +0100963struct lysc_iffeature **
964lysc_node_iff(const struct lysc_node *node)
965{
966 assert(node);
967 switch (node->nodetype) {
968 case LYS_CONTAINER:
969 return &((struct lysc_node_container*)node)->iffeatures;
970 case LYS_LEAF:
971 return &((struct lysc_node_leaf*)node)->iffeatures;
972/* TODO
973 case LYS_LIST:
974 return &((struct lysc_node_list*)node)->iffeatures;
Radek Krejcia3045382018-11-22 14:30:31 +0100975 case LYS_NOTIF:
976 return &((struct lysc_notif*)node)->child;
977*/
978 default:
979 return NULL;
980 }
981}
982
Radek Krejci96a0bfd2018-11-22 15:25:06 +0100983struct lys_module *
984lysp_find_module(struct ly_ctx *ctx, const struct lysp_module *mod)
985{
986 unsigned int u;
987
988 for (u = 0; u < ctx->list.count; ++u) {
989 if (((struct lys_module*)ctx->list.objs[u])->parsed == mod) {
990 return ((struct lys_module*)ctx->list.objs[u]);
991 }
992 }
993 return NULL;
994}
995