blob: 9ba34e942655670dbcb103fb6cf5094fed25cd47 [file] [log] [blame]
Radek Krejci86d106e2018-10-18 09:53:19 +02001/**
2 * @file tree_schema_helpers.c
3 * @author Radek Krejci <rkrejci@cesnet.cz>
Radek Krejcie7b95092019-05-15 11:03:07 +02004 * @brief Parsing and validation helper functions for schema trees
Radek Krejci86d106e2018-10-18 09:53:19 +02005 *
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
Radek Krejcie7b95092019-05-15 11:03:07 +020016#include <assert.h>
17#include <bits/types/struct_tm.h>
Radek Krejci86d106e2018-10-18 09:53:19 +020018#include <ctype.h>
Radek Krejci9ed7a192018-10-31 16:23:51 +010019#include <errno.h>
20#include <fcntl.h>
Radek Krejci86d106e2018-10-18 09:53:19 +020021#include <limits.h>
Radek Krejcie7b95092019-05-15 11:03:07 +020022#include <stdint.h>
Radek Krejci9ed7a192018-10-31 16:23:51 +010023#include <stdlib.h>
Radek Krejcie7b95092019-05-15 11:03:07 +020024#include <string.h>
Radek Krejci9ed7a192018-10-31 16:23:51 +010025#include <unistd.h>
Radek Krejci86d106e2018-10-18 09:53:19 +020026#include <time.h>
27
Radek Krejcie7b95092019-05-15 11:03:07 +020028#include "context.h"
29#include "dict.h"
30#include "extensions.h"
31#include "hash_table.h"
32#include "log.h"
33#include "set.h"
34#include "tree.h"
35#include "tree_schema.h"
Radek Krejci86d106e2018-10-18 09:53:19 +020036#include "tree_schema_internal.h"
37
Radek Krejcia3045382018-11-22 14:30:31 +010038/**
39 * @brief Parse an identifier.
40 *
41 * ;; An identifier MUST NOT start with (('X'|'x') ('M'|'m') ('L'|'l'))
42 * identifier = (ALPHA / "_")
43 * *(ALPHA / DIGIT / "_" / "-" / ".")
44 *
45 * @param[in,out] id Identifier to parse. When returned, it points to the first character which is not part of the identifier.
46 * @return LY_ERR value: LY_SUCCESS or LY_EINVAL in case of invalid starting character.
47 */
48static LY_ERR
49lys_parse_id(const char **id)
50{
51 assert(id && *id);
52
Radek Krejcia9026eb2018-12-12 16:04:47 +010053 if (!is_yangidentstartchar(**id)) {
Radek Krejcia3045382018-11-22 14:30:31 +010054 return LY_EINVAL;
55 }
56 ++(*id);
57
Radek Krejcia9026eb2018-12-12 16:04:47 +010058 while (is_yangidentchar(**id)) {
Radek Krejcia3045382018-11-22 14:30:31 +010059 ++(*id);
60 }
61 return LY_SUCCESS;
62}
63
64LY_ERR
65lys_parse_nodeid(const char **id, const char **prefix, size_t *prefix_len, const char **name, size_t *name_len)
66{
67 assert(id && *id);
68 assert(prefix && prefix_len);
69 assert(name && name_len);
70
71 *prefix = *id;
72 *prefix_len = 0;
73 *name = NULL;
74 *name_len = 0;
75
76 LY_CHECK_RET(lys_parse_id(id));
77 if (**id == ':') {
78 /* there is prefix */
79 *prefix_len = *id - *prefix;
80 ++(*id);
81 *name = *id;
82
83 LY_CHECK_RET(lys_parse_id(id));
84 *name_len = *id - *name;
85 } else {
86 /* there is no prefix, so what we have as prefix now is actually the name */
87 *name = *prefix;
88 *name_len = *id - *name;
89 *prefix = NULL;
90 }
91
92 return LY_SUCCESS;
93}
94
Radek Krejci86d106e2018-10-18 09:53:19 +020095LY_ERR
Radek Krejci95710c92019-02-11 15:49:55 +010096lys_resolve_schema_nodeid(struct lysc_ctx *ctx, const char *nodeid, size_t nodeid_len, const struct lysc_node *context_node,
Radek Krejci6eeb58f2019-02-22 16:29:37 +010097 const struct lys_module *context_module, int nodetype, int implement,
98 const struct lysc_node **target, uint16_t *result_flag)
Radek Krejci9bb94eb2018-12-04 16:48:35 +010099{
100 LY_ERR ret = LY_EVALID;
101 const char *name, *prefix, *id;
Radek Krejci9bb94eb2018-12-04 16:48:35 +0100102 size_t name_len, prefix_len;
Radek Krejci7af64242019-02-18 13:07:53 +0100103 const struct lys_module *mod;
Radek Krejci95710c92019-02-11 15:49:55 +0100104 const char *nodeid_type;
Radek Krejci6eeb58f2019-02-22 16:29:37 +0100105 int getnext_extra_flag = 0;
Radek Krejci05b774b2019-02-25 13:26:18 +0100106 int current_nodetype = 0;
Radek Krejci9bb94eb2018-12-04 16:48:35 +0100107
108 assert(nodeid);
Radek Krejci9bb94eb2018-12-04 16:48:35 +0100109 assert(target);
Radek Krejci6eeb58f2019-02-22 16:29:37 +0100110 assert(result_flag);
Radek Krejci9bb94eb2018-12-04 16:48:35 +0100111 *target = NULL;
Radek Krejci6eeb58f2019-02-22 16:29:37 +0100112 *result_flag = 0;
Radek Krejci9bb94eb2018-12-04 16:48:35 +0100113
114 id = nodeid;
Radek Krejci95710c92019-02-11 15:49:55 +0100115
116 if (context_node) {
117 /* descendant-schema-nodeid */
118 nodeid_type = "descendant";
Radek Krejci3641f562019-02-13 15:38:40 +0100119
120 if (*id == '/') {
121 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
122 "Invalid descendant-schema-nodeid value \"%.*s\" - absolute-schema-nodeid used.",
123 nodeid_len ? nodeid_len : strlen(nodeid), nodeid);
124 return LY_EVALID;
125 }
Radek Krejci95710c92019-02-11 15:49:55 +0100126 } else {
127 /* absolute-schema-nodeid */
128 nodeid_type = "absolute";
Radek Krejci95710c92019-02-11 15:49:55 +0100129
130 if (*id != '/') {
131 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
132 "Invalid absolute-schema-nodeid value \"%.*s\" - missing starting \"/\".",
Radek Krejci3641f562019-02-13 15:38:40 +0100133 nodeid_len ? nodeid_len : strlen(nodeid), nodeid);
Radek Krejci95710c92019-02-11 15:49:55 +0100134 return LY_EVALID;
135 }
136 ++id;
137 }
138
Radek Krejci9bb94eb2018-12-04 16:48:35 +0100139 while (*id && (ret = lys_parse_nodeid(&id, &prefix, &prefix_len, &name, &name_len)) == LY_SUCCESS) {
140 if (prefix) {
Radek Krejci95710c92019-02-11 15:49:55 +0100141 mod = lys_module_find_prefix(context_module, prefix, prefix_len);
Radek Krejci9bb94eb2018-12-04 16:48:35 +0100142 if (!mod) {
143 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
Radek Krejci95710c92019-02-11 15:49:55 +0100144 "Invalid %s-schema-nodeid value \"%.*s\" - prefix \"%.*s\" not defined in module \"%s\".",
145 nodeid_type, id - nodeid, nodeid, prefix_len, prefix, context_module->name);
Radek Krejci9bb94eb2018-12-04 16:48:35 +0100146 return LY_ENOTFOUND;
147 }
148 } else {
Radek Krejci95710c92019-02-11 15:49:55 +0100149 mod = context_module;
150 }
151 if (implement && !mod->implemented) {
152 /* make the module implemented */
153 ly_ctx_module_implement_internal(ctx->ctx, (struct lys_module*)mod, 2);
Radek Krejci9bb94eb2018-12-04 16:48:35 +0100154 }
Radek Krejci6eeb58f2019-02-22 16:29:37 +0100155 if (context_node && context_node->nodetype == LYS_ACTION) {
156 /* move through input/output manually */
157 if (!strncmp("input", name, name_len)) {
158 (*result_flag) |= LYSC_OPT_RPC_INPUT;
Radek Krejci05b774b2019-02-25 13:26:18 +0100159 } else if (!strncmp("output", name, name_len)) {
Radek Krejci6eeb58f2019-02-22 16:29:37 +0100160 (*result_flag) |= LYSC_OPT_RPC_OUTPUT;
161 getnext_extra_flag = LYS_GETNEXT_OUTPUT;
Radek Krejci05b774b2019-02-25 13:26:18 +0100162 } else {
163 goto getnext;
Radek Krejci6eeb58f2019-02-22 16:29:37 +0100164 }
Radek Krejci05b774b2019-02-25 13:26:18 +0100165 current_nodetype = LYS_INOUT;
Radek Krejci6eeb58f2019-02-22 16:29:37 +0100166 } else {
Radek Krejci05b774b2019-02-25 13:26:18 +0100167getnext:
Radek Krejci6eeb58f2019-02-22 16:29:37 +0100168 context_node = lys_child(context_node, mod, name, name_len, 0,
169 getnext_extra_flag | LYS_GETNEXT_NOSTATECHECK | LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE);
170 if (!context_node) {
171 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
172 "Invalid %s-schema-nodeid value \"%.*s\" - target node not found.", nodeid_type, id - nodeid, nodeid);
173 return LY_ENOTFOUND;
174 }
175 getnext_extra_flag = 0;
Radek Krejci05b774b2019-02-25 13:26:18 +0100176 current_nodetype = context_node->nodetype;
Radek Krejci6eeb58f2019-02-22 16:29:37 +0100177
Radek Krejci05b774b2019-02-25 13:26:18 +0100178 if (current_nodetype == LYS_NOTIF) {
Radek Krejci6eeb58f2019-02-22 16:29:37 +0100179 (*result_flag) |= LYSC_OPT_NOTIFICATION;
180 }
Radek Krejci9bb94eb2018-12-04 16:48:35 +0100181 }
Radek Krejci01342af2019-01-03 15:18:08 +0100182 if (!*id || (nodeid_len && ((size_t)(id - nodeid) >= nodeid_len))) {
Radek Krejci9bb94eb2018-12-04 16:48:35 +0100183 break;
184 }
Radek Krejci01342af2019-01-03 15:18:08 +0100185 if (*id != '/') {
Radek Krejci9bb94eb2018-12-04 16:48:35 +0100186 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
Radek Krejci95710c92019-02-11 15:49:55 +0100187 "Invalid %s-schema-nodeid value \"%.*s\" - missing \"/\" as node-identifier separator.",
188 nodeid_type, id - nodeid + 1, nodeid);
Radek Krejci9bb94eb2018-12-04 16:48:35 +0100189 return LY_EVALID;
190 }
191 ++id;
192 }
193
194 if (ret == LY_SUCCESS) {
Radek Krejci7af64242019-02-18 13:07:53 +0100195 *target = context_node;
Radek Krejci05b774b2019-02-25 13:26:18 +0100196 if (nodetype & LYS_INOUT) {
197 /* instead of input/output nodes, the RPC/action node is actually returned */
198 }
199 if (nodetype && !(current_nodetype & nodetype)) {
Radek Krejci9bb94eb2018-12-04 16:48:35 +0100200 return LY_EDENIED;
201 }
Radek Krejci95710c92019-02-11 15:49:55 +0100202 } else {
203 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
204 "Invalid %s-schema-nodeid value \"%.*s\" - unexpected end of expression.",
Radek Krejci3641f562019-02-13 15:38:40 +0100205 nodeid_type, nodeid_len ? nodeid_len : strlen(nodeid), nodeid);
Radek Krejci9bb94eb2018-12-04 16:48:35 +0100206 }
207
208 return ret;
209}
210
211LY_ERR
Radek Krejcie7b95092019-05-15 11:03:07 +0200212lysp_check_prefix(struct lys_parser_ctx *ctx, struct lysp_import *imports, const char *module_prefix, const char **value)
Radek Krejci86d106e2018-10-18 09:53:19 +0200213{
214 struct lysp_import *i;
215
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100216 if (module_prefix && &module_prefix != value && !strcmp(module_prefix, *value)) {
Radek Krejci86d106e2018-10-18 09:53:19 +0200217 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_REFERENCE,
218 "Prefix \"%s\" already used as module prefix.", *value);
219 return LY_EEXIST;
220 }
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100221 LY_ARRAY_FOR(imports, struct lysp_import, i) {
222 if (i->prefix && &i->prefix != value && !strcmp(i->prefix, *value)) {
223 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_REFERENCE, "Prefix \"%s\" already used to import \"%s\" module.",
224 *value, i->name);
225 return LY_EEXIST;
Radek Krejci86d106e2018-10-18 09:53:19 +0200226 }
227 }
228 return LY_SUCCESS;
229}
230
231LY_ERR
Radek Krejci4f28eda2018-11-12 11:46:16 +0100232lysc_check_status(struct lysc_ctx *ctx,
233 uint16_t flags1, void *mod1, const char *name1,
234 uint16_t flags2, void *mod2, const char *name2)
235{
236 uint16_t flg1, flg2;
237
238 flg1 = (flags1 & LYS_STATUS_MASK) ? (flags1 & LYS_STATUS_MASK) : LYS_STATUS_CURR;
239 flg2 = (flags2 & LYS_STATUS_MASK) ? (flags2 & LYS_STATUS_MASK) : LYS_STATUS_CURR;
240
241 if ((flg1 < flg2) && (mod1 == mod2)) {
242 if (ctx) {
243 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
244 "A %s definition \"%s\" is not allowed to reference %s definition \"%s\".",
245 flg1 == LYS_STATUS_CURR ? "current" : "deprecated", name1,
246 flg2 == LYS_STATUS_OBSLT ? "obsolete" : "deprecated", name2);
247 }
248 return LY_EVALID;
249 }
250
251 return LY_SUCCESS;
252}
253
254LY_ERR
Radek Krejcie7b95092019-05-15 11:03:07 +0200255lysp_check_date(struct lys_parser_ctx *ctx, const char *date, int date_len, const char *stmt)
Radek Krejci86d106e2018-10-18 09:53:19 +0200256{
257 int i;
258 struct tm tm, tm_;
259 char *r;
260
Radek Krejcibbe09a92018-11-08 09:36:54 +0100261 LY_CHECK_ARG_RET(ctx ? ctx->ctx : NULL, date, LY_EINVAL);
262 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 +0200263
264 /* check format */
265 for (i = 0; i < date_len; i++) {
266 if (i == 4 || i == 7) {
267 if (date[i] != '-') {
268 goto error;
269 }
270 } else if (!isdigit(date[i])) {
271 goto error;
272 }
273 }
274
275 /* check content, e.g. 2018-02-31 */
276 memset(&tm, 0, sizeof tm);
277 r = strptime(date, "%Y-%m-%d", &tm);
278 if (!r || r != &date[LY_REV_SIZE - 1]) {
279 goto error;
280 }
281 memcpy(&tm_, &tm, sizeof tm);
282 mktime(&tm_); /* mktime modifies tm_ if it refers invalid date */
283 if (tm.tm_mday != tm_.tm_mday) { /* e.g 2018-02-29 -> 2018-03-01 */
284 /* checking days is enough, since other errors
285 * have been checked by strptime() */
286 goto error;
287 }
288
289 return LY_SUCCESS;
290
291error:
Radek Krejcid33273d2018-10-25 14:55:52 +0200292 if (stmt) {
Radek Krejcibbe09a92018-11-08 09:36:54 +0100293 if (ctx) {
294 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LY_VCODE_INVAL, date_len, date, stmt);
295 } else {
296 LOGVAL(NULL, LY_VLOG_NONE, NULL, LY_VCODE_INVAL, date_len, date, stmt);
297 }
Radek Krejcid33273d2018-10-25 14:55:52 +0200298 }
Radek Krejci86d106e2018-10-18 09:53:19 +0200299 return LY_EINVAL;
300}
301
302void
303lysp_sort_revisions(struct lysp_revision *revs)
304{
305 uint8_t i, r;
306 struct lysp_revision rev;
307
308 for (i = 1, r = 0; revs && i < LY_ARRAY_SIZE(revs); i++) {
Radek Krejcib7db73a2018-10-24 14:18:40 +0200309 if (strcmp(revs[i].date, revs[r].date) > 0) {
Radek Krejci86d106e2018-10-18 09:53:19 +0200310 r = i;
311 }
312 }
313
314 if (r) {
315 /* the newest revision is not on position 0, switch them */
Radek Krejci2c4e7172018-10-19 15:56:26 +0200316 memcpy(&rev, &revs[0], sizeof rev);
317 memcpy(&revs[0], &revs[r], sizeof rev);
318 memcpy(&revs[r], &rev, sizeof rev);
Radek Krejci86d106e2018-10-18 09:53:19 +0200319 }
320}
Radek Krejci151a5b72018-10-19 14:21:44 +0200321
Radek Krejcibbe09a92018-11-08 09:36:54 +0100322static const struct lysp_tpdf *
323lysp_type_match(const char *name, struct lysp_node *node)
324{
Radek Krejci0fb28562018-12-13 15:17:37 +0100325 const struct lysp_tpdf *typedefs;
Radek Krejcibbe09a92018-11-08 09:36:54 +0100326 unsigned int u;
327
Radek Krejci0fb28562018-12-13 15:17:37 +0100328 typedefs = lysp_node_typedefs(node);
329 LY_ARRAY_FOR(typedefs, u) {
330 if (!strcmp(name, typedefs[u].name)) {
331 /* match */
332 return &typedefs[u];
Radek Krejcibbe09a92018-11-08 09:36:54 +0100333 }
334 }
335
336 return NULL;
337}
338
Radek Krejci4f28eda2018-11-12 11:46:16 +0100339static LY_DATA_TYPE
340lysp_type_str2builtin(const char *name, size_t len)
341{
342 if (len >= 4) { /* otherwise it does not match any built-in type */
343 if (name[0] == 'b') {
344 if (name[1] == 'i') {
345 if (len == 6 && !strncmp(&name[2], "nary", 4)) {
346 return LY_TYPE_BINARY;
347 } else if (len == 4 && !strncmp(&name[2], "ts", 2)) {
348 return LY_TYPE_BITS;
349 }
350 } else if (len == 7 && !strncmp(&name[1], "oolean", 6)) {
351 return LY_TYPE_BOOL;
352 }
353 } else if (name[0] == 'd') {
354 if (len == 9 && !strncmp(&name[1], "ecimal64", 8)) {
355 return LY_TYPE_DEC64;
356 }
357 } else if (name[0] == 'e') {
358 if (len == 5 && !strncmp(&name[1], "mpty", 4)) {
359 return LY_TYPE_EMPTY;
360 } else if (len == 11 && !strncmp(&name[1], "numeration", 10)) {
361 return LY_TYPE_ENUM;
362 }
363 } else if (name[0] == 'i') {
364 if (name[1] == 'n') {
365 if (len == 4 && !strncmp(&name[2], "t8", 2)) {
366 return LY_TYPE_INT8;
367 } else if (len == 5) {
368 if (!strncmp(&name[2], "t16", 3)) {
369 return LY_TYPE_INT16;
370 } else if (!strncmp(&name[2], "t32", 3)) {
371 return LY_TYPE_INT32;
372 } else if (!strncmp(&name[2], "t64", 3)) {
373 return LY_TYPE_INT64;
374 }
375 } else if (len == 19 && !strncmp(&name[2], "stance-identifier", 17)) {
376 return LY_TYPE_INST;
377 }
378 } else if (len == 11 && !strncmp(&name[1], "dentityref", 10)) {
379 return LY_TYPE_IDENT;
380 }
381 } else if (name[0] == 'l') {
382 if (len == 7 && !strncmp(&name[1], "eafref", 6)) {
383 return LY_TYPE_LEAFREF;
384 }
385 } else if (name[0] == 's') {
386 if (len == 6 && !strncmp(&name[1], "tring", 5)) {
387 return LY_TYPE_STRING;
388 }
389 } else if (name[0] == 'u') {
390 if (name[1] == 'n') {
391 if (len == 5 && !strncmp(&name[2], "ion", 3)) {
392 return LY_TYPE_UNION;
393 }
394 } else if (name[1] == 'i' && name[2] == 'n' && name[3] == 't') {
395 if (len == 5 && name[4] == '8') {
396 return LY_TYPE_UINT8;
397 } else if (len == 6) {
398 if (!strncmp(&name[4], "16", 2)) {
399 return LY_TYPE_UINT16;
400 } else if (!strncmp(&name[4], "32", 2)) {
401 return LY_TYPE_UINT32;
402 } else if (!strncmp(&name[4], "64", 2)) {
403 return LY_TYPE_UINT64;
404 }
405 }
406 }
407 }
408 }
409
410 return LY_TYPE_UNKNOWN;
411}
412
Radek Krejcibbe09a92018-11-08 09:36:54 +0100413LY_ERR
414lysp_type_find(const char *id, struct lysp_node *start_node, struct lysp_module *start_module,
Radek Krejci4f28eda2018-11-12 11:46:16 +0100415 LY_DATA_TYPE *type, const struct lysp_tpdf **tpdf, struct lysp_node **node, struct lysp_module **module)
Radek Krejcibbe09a92018-11-08 09:36:54 +0100416{
417 const char *str, *name;
418 struct lysp_tpdf *typedefs;
419 unsigned int u, v;
420
421 assert(id);
422 assert(start_module);
423 assert(tpdf);
424 assert(node);
425 assert(module);
426
Radek Krejci4f28eda2018-11-12 11:46:16 +0100427 *node = NULL;
Radek Krejcibbe09a92018-11-08 09:36:54 +0100428 str = strchr(id, ':');
429 if (str) {
430 *module = lysp_module_find_prefix(start_module, id, str - id);
431 name = str + 1;
Radek Krejci4f28eda2018-11-12 11:46:16 +0100432 *type = LY_TYPE_UNKNOWN;
Radek Krejcibbe09a92018-11-08 09:36:54 +0100433 } else {
434 *module = start_module;
435 name = id;
Radek Krejci4f28eda2018-11-12 11:46:16 +0100436
437 /* check for built-in types */
438 *type = lysp_type_str2builtin(name, strlen(name));
439 if (*type) {
440 *tpdf = NULL;
441 return LY_SUCCESS;
442 }
Radek Krejcibbe09a92018-11-08 09:36:54 +0100443 }
444 LY_CHECK_RET(!(*module), LY_ENOTFOUND);
445
446 if (start_node && *module == start_module) {
447 /* search typedefs in parent's nodes */
448 *node = start_node;
449 while (*node) {
450 *tpdf = lysp_type_match(name, *node);
451 if (*tpdf) {
452 /* match */
453 return LY_SUCCESS;
454 }
455 *node = (*node)->parent;
456 }
457 }
458
459 /* search in top-level typedefs */
460 if ((*module)->typedefs) {
461 LY_ARRAY_FOR((*module)->typedefs, u) {
462 if (!strcmp(name, (*module)->typedefs[u].name)) {
463 /* match */
464 *tpdf = &(*module)->typedefs[u];
465 return LY_SUCCESS;
466 }
467 }
468 }
469
470 /* search in submodules' typedefs */
471 LY_ARRAY_FOR((*module)->includes, u) {
472 typedefs = (*module)->includes[u].submodule->typedefs;
Radek Krejci76b3e962018-12-14 17:01:25 +0100473 LY_ARRAY_FOR(typedefs, v) {
474 if (!strcmp(name, typedefs[v].name)) {
475 /* match */
476 *tpdf = &typedefs[v];
477 return LY_SUCCESS;
Radek Krejcibbe09a92018-11-08 09:36:54 +0100478 }
479 }
480 }
481
482 return LY_ENOTFOUND;
483}
484
485/*
486 * @brief Check name of a new type to avoid name collisions.
487 *
488 * @param[in] ctx Parser context, module where the type is being defined is taken from here.
489 * @param[in] node Schema node where the type is being defined, NULL in case of a top-level typedef.
490 * @param[in] tpdf Typedef definition to check.
491 * @param[in,out] tpdfs_global Initialized hash table to store temporary data between calls. When the module's
492 * typedefs are checked, caller is supposed to free the table.
493 * @param[in,out] tpdfs_global Initialized hash table to store temporary data between calls. When the module's
494 * typedefs are checked, caller is supposed to free the table.
495 * @return LY_EEXIST in case of collision, LY_SUCCESS otherwise.
496 */
497static LY_ERR
Radek Krejcie7b95092019-05-15 11:03:07 +0200498lysp_check_typedef(struct lys_parser_ctx *ctx, struct lysp_node *node, const struct lysp_tpdf *tpdf,
Radek Krejcibbe09a92018-11-08 09:36:54 +0100499 struct hash_table *tpdfs_global, struct hash_table *tpdfs_scoped)
500{
501 struct lysp_node *parent;
502 uint32_t hash;
503 size_t name_len;
504 const char *name;
505 unsigned int u;
Radek Krejci0fb28562018-12-13 15:17:37 +0100506 const struct lysp_tpdf *typedefs;
Radek Krejcibbe09a92018-11-08 09:36:54 +0100507
508 assert(ctx);
509 assert(tpdf);
510
511 name = tpdf->name;
512 name_len = strlen(name);
513
Radek Krejci4f28eda2018-11-12 11:46:16 +0100514 if (lysp_type_str2builtin(name, name_len)) {
515 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_SYNTAX_YANG,
516 "Invalid name \"%s\" of typedef - name collision with a built-in type.", name);
517 return LY_EEXIST;
Radek Krejcibbe09a92018-11-08 09:36:54 +0100518 }
519
520 /* check locally scoped typedefs (avoid name shadowing) */
521 if (node) {
Radek Krejci0fb28562018-12-13 15:17:37 +0100522 typedefs = lysp_node_typedefs(node);
523 LY_ARRAY_FOR(typedefs, u) {
524 if (&typedefs[u] == tpdf) {
525 break;
526 }
527 if (!strcmp(name, typedefs[u].name)) {
528 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_SYNTAX_YANG,
529 "Invalid name \"%s\" of typedef - name collision with sibling type.", name);
530 return LY_EEXIST;
Radek Krejcibbe09a92018-11-08 09:36:54 +0100531 }
532 }
533 /* search typedefs in parent's nodes */
Radek Krejci87e78ca2019-05-02 09:51:29 +0200534 for (parent = node->parent; parent; parent = parent->parent) {
Radek Krejcibbe09a92018-11-08 09:36:54 +0100535 if (lysp_type_match(name, parent)) {
536 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_SYNTAX_YANG,
537 "Invalid name \"%s\" of typedef - name collision with another scoped type.", name);
538 return LY_EEXIST;
539 }
540 }
541 }
542
543 /* check collision with the top-level typedefs */
544 hash = dict_hash(name, name_len);
545 if (node) {
546 lyht_insert(tpdfs_scoped, &name, hash, NULL);
547 if (!lyht_find(tpdfs_global, &name, hash, NULL)) {
548 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_SYNTAX_YANG,
549 "Invalid name \"%s\" of typedef - scoped type collide with a top-level type.", name);
550 return LY_EEXIST;
551 }
552 } else {
553 if (lyht_insert(tpdfs_global, &name, hash, NULL)) {
554 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_SYNTAX_YANG,
555 "Invalid name \"%s\" of typedef - name collision with another top-level type.", name);
556 return LY_EEXIST;
557 }
Radek Krejci3b1f9292018-11-08 10:58:35 +0100558 /* it is not necessary to test collision with the scoped types - in lysp_check_typedefs, all the
559 * top-level typedefs are inserted into the tables before the scoped typedefs, so the collision
560 * is detected in the first branch few lines above */
Radek Krejcibbe09a92018-11-08 09:36:54 +0100561 }
562
563 return LY_SUCCESS;
564}
565
566static int
567lysp_id_cmp(void *val1, void *val2, int UNUSED(mod), void *UNUSED(cb_data))
568{
569 return !strcmp(val1, val2);
570}
571
572LY_ERR
Radek Krejcie7b95092019-05-15 11:03:07 +0200573lysp_check_typedefs(struct lys_parser_ctx *ctx, struct lysp_module *mod)
Radek Krejcibbe09a92018-11-08 09:36:54 +0100574{
575 struct hash_table *ids_global;
576 struct hash_table *ids_scoped;
Radek Krejci0fb28562018-12-13 15:17:37 +0100577 const struct lysp_tpdf *typedefs;
Radek Krejcibbe09a92018-11-08 09:36:54 +0100578 unsigned int i, u;
579 LY_ERR ret = LY_EVALID;
580
581 /* check name collisions - typedefs and groupings */
582 ids_global = lyht_new(8, sizeof(char*), lysp_id_cmp, NULL, 1);
583 ids_scoped = lyht_new(8, sizeof(char*), lysp_id_cmp, NULL, 1);
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100584 LY_ARRAY_FOR(mod->typedefs, i) {
585 if (lysp_check_typedef(ctx, NULL, &mod->typedefs[i], ids_global, ids_scoped)) {
Radek Krejcibbe09a92018-11-08 09:36:54 +0100586 goto cleanup;
587 }
588 }
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100589 LY_ARRAY_FOR(mod->includes, i) {
590 LY_ARRAY_FOR(mod->includes[i].submodule->typedefs, u) {
591 if (lysp_check_typedef(ctx, NULL, &mod->includes[i].submodule->typedefs[u], ids_global, ids_scoped)) {
Radek Krejci3b1f9292018-11-08 10:58:35 +0100592 goto cleanup;
593 }
594 }
595 }
Radek Krejcibbe09a92018-11-08 09:36:54 +0100596 for (u = 0; u < ctx->tpdfs_nodes.count; ++u) {
Radek Krejci0fb28562018-12-13 15:17:37 +0100597 typedefs = lysp_node_typedefs((struct lysp_node *)ctx->tpdfs_nodes.objs[u]);
598 LY_ARRAY_FOR(typedefs, i) {
599 if (lysp_check_typedef(ctx, (struct lysp_node *)ctx->tpdfs_nodes.objs[u], &typedefs[i], ids_global, ids_scoped)) {
Radek Krejcibbe09a92018-11-08 09:36:54 +0100600 goto cleanup;
601 }
602 }
603 }
604 ret = LY_SUCCESS;
605cleanup:
606 lyht_free(ids_global);
607 lyht_free(ids_scoped);
608 ly_set_erase(&ctx->tpdfs_nodes, NULL);
609
610 return ret;
611}
612
Radek Krejci9ed7a192018-10-31 16:23:51 +0100613struct lysp_load_module_check_data {
614 const char *name;
615 const char *revision;
616 const char *path;
617 const char* submoduleof;
618};
619
620static LY_ERR
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100621lysp_load_module_check(struct ly_ctx *ctx, struct lysp_module *mod, struct lysp_submodule *submod, void *data)
Radek Krejci9ed7a192018-10-31 16:23:51 +0100622{
623 struct lysp_load_module_check_data *info = data;
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100624 const char *filename, *dot, *rev, *name;
Radek Krejci9ed7a192018-10-31 16:23:51 +0100625 size_t len;
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100626 struct lysp_revision *revs;
627
628 name = mod ? mod->mod->name : submod->name;
629 revs = mod ? mod->revs : submod->revs;
Radek Krejci9ed7a192018-10-31 16:23:51 +0100630
631 if (info->name) {
632 /* check name of the parsed model */
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100633 if (strcmp(info->name, name)) {
634 LOGERR(ctx, LY_EINVAL, "Unexpected module \"%s\" parsed instead of \"%s\").", name, info->name);
Radek Krejci9ed7a192018-10-31 16:23:51 +0100635 return LY_EINVAL;
636 }
637 }
638 if (info->revision) {
639 /* check revision of the parsed model */
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100640 if (!revs || strcmp(info->revision, revs[0].date)) {
641 LOGERR(ctx, LY_EINVAL, "Module \"%s\" parsed with the wrong revision (\"%s\" instead \"%s\").", name,
Radek Krejcib07b5c92019-04-08 10:56:37 +0200642 revs ? revs[0].date : "none", info->revision);
Radek Krejci9ed7a192018-10-31 16:23:51 +0100643 return LY_EINVAL;
644 }
645 }
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100646 if (submod) {
647 assert(info->submoduleof);
648
Radek Krejci9ed7a192018-10-31 16:23:51 +0100649 /* check that the submodule belongs-to our module */
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100650 if (strcmp(info->submoduleof, submod->belongsto)) {
Radek Krejci9ed7a192018-10-31 16:23:51 +0100651 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE, "Included \"%s\" submodule from \"%s\" belongs-to a different module \"%s\".",
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100652 submod->name, info->submoduleof, submod->belongsto);
Radek Krejci9ed7a192018-10-31 16:23:51 +0100653 return LY_EVALID;
654 }
655 /* check circular dependency */
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100656 if (submod->parsing) {
657 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE, "A circular dependency (include) for module \"%s\".", submod->name);
Radek Krejci9ed7a192018-10-31 16:23:51 +0100658 return LY_EVALID;
659 }
660 }
661 if (info->path) {
662 /* check that name and revision match filename */
663 filename = strrchr(info->path, '/');
664 if (!filename) {
665 filename = info->path;
666 } else {
667 filename++;
668 }
669 /* name */
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100670 len = strlen(name);
Radek Krejci9ed7a192018-10-31 16:23:51 +0100671 rev = strchr(filename, '@');
672 dot = strrchr(info->path, '.');
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100673 if (strncmp(filename, name, len) ||
Radek Krejci9ed7a192018-10-31 16:23:51 +0100674 ((rev && rev != &filename[len]) || (!rev && dot != &filename[len]))) {
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100675 LOGWRN(ctx, "File name \"%s\" does not match module name \"%s\".", filename, name);
Radek Krejci9ed7a192018-10-31 16:23:51 +0100676 }
677 /* revision */
678 if (rev) {
679 len = dot - ++rev;
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100680 if (!revs || len != 10 || strncmp(revs[0].date, rev, len)) {
Radek Krejci9ed7a192018-10-31 16:23:51 +0100681 LOGWRN(ctx, "File name \"%s\" does not match module revision \"%s\".", filename,
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100682 revs ? revs[0].date : "none");
Radek Krejci9ed7a192018-10-31 16:23:51 +0100683 }
684 }
685 }
686 return LY_SUCCESS;
687}
688
689LY_ERR
Radek Krejcie7b95092019-05-15 11:03:07 +0200690lys_module_localfile(struct ly_ctx *ctx, const char *name, const char *revision, int implement, struct lys_parser_ctx *main_ctx,
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100691 void **result)
Radek Krejci9ed7a192018-10-31 16:23:51 +0100692{
693 int fd;
694 char *filepath = NULL;
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100695 const char **fp;
Radek Krejci9ed7a192018-10-31 16:23:51 +0100696 LYS_INFORMAT format;
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100697 void *mod = NULL;
Radek Krejci9ed7a192018-10-31 16:23:51 +0100698 LY_ERR ret = LY_SUCCESS;
699 struct lysp_load_module_check_data check_data = {0};
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100700 char rpath[PATH_MAX];
Radek Krejci9ed7a192018-10-31 16:23:51 +0100701
702 LY_CHECK_RET(lys_search_localfile(ly_ctx_get_searchdirs(ctx), !(ctx->flags & LY_CTX_DISABLE_SEARCHDIR_CWD), name, revision,
703 &filepath, &format));
704 LY_CHECK_ERR_RET(!filepath, LOGERR(ctx, LY_ENOTFOUND, "Data model \"%s%s%s\" not found in local searchdirs.",
705 name, revision ? "@" : "", revision ? revision : ""), LY_ENOTFOUND);
706
707
708 LOGVRB("Loading schema from \"%s\" file.", filepath);
709
710 /* open the file */
711 fd = open(filepath, O_RDONLY);
712 LY_CHECK_ERR_GOTO(fd < 0, LOGERR(ctx, LY_ESYS, "Unable to open data model file \"%s\" (%s).",
713 filepath, strerror(errno)); ret = LY_ESYS, cleanup);
714
715 check_data.name = name;
716 check_data.revision = revision;
717 check_data.path = filepath;
Radek Krejci3b1f9292018-11-08 10:58:35 +0100718 mod = lys_parse_fd_(ctx, fd, format, implement, main_ctx,
Radek Krejci9ed7a192018-10-31 16:23:51 +0100719 lysp_load_module_check, &check_data);
720 close(fd);
721 LY_CHECK_ERR_GOTO(!mod, ly_errcode(ctx), cleanup);
722
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100723 if (main_ctx) {
724 fp = &((struct lysp_submodule*)mod)->filepath;
725 } else {
726 fp = &((struct lys_module*)mod)->filepath;
727 }
728 if (!(*fp)) {
Radek Krejci9ed7a192018-10-31 16:23:51 +0100729 if (realpath(filepath, rpath) != NULL) {
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100730 (*fp) = lydict_insert(ctx, rpath, 0);
Radek Krejci9ed7a192018-10-31 16:23:51 +0100731 } else {
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100732 (*fp) = lydict_insert(ctx, filepath, 0);
Radek Krejci9ed7a192018-10-31 16:23:51 +0100733 }
734 }
735
736 *result = mod;
737
738 /* success */
739cleanup:
740 free(filepath);
741 return ret;
742}
743
Radek Krejcid33273d2018-10-25 14:55:52 +0200744LY_ERR
Radek Krejci6d6e4e42018-10-29 13:28:19 +0100745lysp_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 +0200746{
Radek Krejci9ed7a192018-10-31 16:23:51 +0100747 const char *module_data = NULL;
Radek Krejci086c7132018-10-26 15:29:04 +0200748 LYS_INFORMAT format = LYS_IN_UNKNOWN;
Radek Krejci9ed7a192018-10-31 16:23:51 +0100749 void (*module_data_free)(void *module_data, void *user_data) = NULL;
750 struct lysp_load_module_check_data check_data = {0};
Radek Krejci0af46292019-01-11 16:02:31 +0100751 struct lys_module *m;
Radek Krejci086c7132018-10-26 15:29:04 +0200752
Radek Krejci0af46292019-01-11 16:02:31 +0100753 assert(mod);
754
755 if (!*mod) {
756 /* try to get the module from the context */
757 if (revision) {
Radek Krejcied5acc52019-04-25 15:57:04 +0200758 /* get the specific revision */
Radek Krejci0af46292019-01-11 16:02:31 +0100759 *mod = (struct lys_module*)ly_ctx_get_module(ctx, name, revision);
Radek Krejcied5acc52019-04-25 15:57:04 +0200760 } else if (implement) {
761 /* prefer the implemented module instead of the latest one */
762 *mod = (struct lys_module*)ly_ctx_get_module_implemented(ctx, name);
763 if (!*mod) {
764 /* there is no implemented module in the context, try to get the latest revision module */
765 goto latest_in_the_context;
766 }
Radek Krejci0af46292019-01-11 16:02:31 +0100767 } else {
Radek Krejcied5acc52019-04-25 15:57:04 +0200768 /* get the requested module of the latest revision in the context */
769latest_in_the_context:
Radek Krejci0af46292019-01-11 16:02:31 +0100770 *mod = (struct lys_module*)ly_ctx_get_module_latest(ctx, name);
771 }
Radek Krejci086c7132018-10-26 15:29:04 +0200772 }
773
Radek Krejci6d6e4e42018-10-29 13:28:19 +0100774 if (!(*mod) || (require_parsed && !(*mod)->parsed)) {
775 (*mod) = NULL;
776
Radek Krejci086c7132018-10-26 15:29:04 +0200777 /* check collision with other implemented revision */
778 if (implement && ly_ctx_get_module_implemented(ctx, name)) {
779 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE,
780 "Module \"%s\" is already present in other implemented revision.", name);
781 return LY_EDENIED;
782 }
783
Radek Krejci9ed7a192018-10-31 16:23:51 +0100784 /* module not present in the context, get the input data and parse it */
Radek Krejci086c7132018-10-26 15:29:04 +0200785 if (!(ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
786search_clb:
787 if (ctx->imp_clb) {
788 if (ctx->imp_clb(name, revision, NULL, NULL, ctx->imp_clb_data,
Radek Krejci9ed7a192018-10-31 16:23:51 +0100789 &format, &module_data, &module_data_free) == LY_SUCCESS) {
790 check_data.name = name;
791 check_data.revision = revision;
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100792 *mod = lys_parse_mem_module(ctx, module_data, format, implement,
793 lysp_load_module_check, &check_data);
Radek Krejci9ed7a192018-10-31 16:23:51 +0100794 if (module_data_free) {
795 module_data_free((void*)module_data, ctx->imp_clb_data);
796 }
Radek Krejci096235c2019-01-11 11:12:19 +0100797 if (*mod && implement && lys_compile(*mod, 0)) {
798 ly_set_rm(&ctx->list, *mod, NULL);
799 lys_module_free(*mod, NULL);
800 *mod = NULL;
801 }
Radek Krejci086c7132018-10-26 15:29:04 +0200802 }
803 }
804 if (!(*mod) && !(ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
805 goto search_file;
806 }
807 } else {
808search_file:
809 if (!(ctx->flags & LY_CTX_DISABLE_SEARCHDIRS)) {
810 /* module was not received from the callback or there is no callback set */
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100811 lys_module_localfile(ctx, name, revision, implement, NULL, (void **)mod);
Radek Krejci086c7132018-10-26 15:29:04 +0200812 }
813 if (!(*mod) && (ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
814 goto search_clb;
815 }
816 }
Radek Krejci9ed7a192018-10-31 16:23:51 +0100817
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100818 if ((*mod) && !revision && ((*mod)->latest_revision == 1)) {
Radek Krejci9ed7a192018-10-31 16:23:51 +0100819 /* update the latest_revision flag - here we have selected the latest available schema,
820 * consider that even the callback provides correct latest revision */
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100821 (*mod)->latest_revision = 2;
Radek Krejci9ed7a192018-10-31 16:23:51 +0100822 }
Radek Krejci086c7132018-10-26 15:29:04 +0200823 } else {
824 /* we have module from the current context */
Radek Krejci0af46292019-01-11 16:02:31 +0100825 if (implement) {
826 m = ly_ctx_get_module_implemented(ctx, name);
827 if (m && m != *mod) {
828 /* check collision with other implemented revision */
829 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE,
830 "Module \"%s\" is already present in other implemented revision.", name);
831 *mod = NULL;
832 return LY_EDENIED;
833 }
Radek Krejci086c7132018-10-26 15:29:04 +0200834 }
835
836 /* circular check */
Radek Krejcif8f882a2018-10-31 14:51:15 +0100837 if ((*mod)->parsed && (*mod)->parsed->parsing) {
Radek Krejci086c7132018-10-26 15:29:04 +0200838 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE, "A circular dependency (import) for module \"%s\".", name);
839 *mod = NULL;
840 return LY_EVALID;
841 }
842 }
843 if (!(*mod)) {
Radek Krejci9ed7a192018-10-31 16:23:51 +0100844 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE, "%s \"%s\" module failed.", implement ? "Loading" : "Importing", name);
Radek Krejci086c7132018-10-26 15:29:04 +0200845 return LY_EVALID;
846 }
847
848 if (implement) {
849 /* mark the module implemented, check for collision was already done */
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100850 (*mod)->implemented = 1;
Radek Krejci086c7132018-10-26 15:29:04 +0200851 }
Radek Krejci086c7132018-10-26 15:29:04 +0200852
853 return LY_SUCCESS;
854}
855
856LY_ERR
Radek Krejcie7b95092019-05-15 11:03:07 +0200857lysp_load_submodule(struct lys_parser_ctx *ctx, struct lysp_module *mod, struct lysp_include *inc)
Radek Krejcid33273d2018-10-25 14:55:52 +0200858{
Radek Krejci3eb299d2019-04-08 15:07:44 +0200859 struct lysp_submodule *submod = NULL;
Radek Krejcid33273d2018-10-25 14:55:52 +0200860 const char *submodule_data = NULL;
861 LYS_INFORMAT format = LYS_IN_UNKNOWN;
862 void (*submodule_data_free)(void *module_data, void *user_data) = NULL;
Radek Krejci9ed7a192018-10-31 16:23:51 +0100863 struct lysp_load_module_check_data check_data = {0};
Radek Krejcid33273d2018-10-25 14:55:52 +0200864
Radek Krejcibbe09a92018-11-08 09:36:54 +0100865 /* submodule not present in the context, get the input data and parse it */
Radek Krejci3b1f9292018-11-08 10:58:35 +0100866 if (!(ctx->ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
Radek Krejcid33273d2018-10-25 14:55:52 +0200867search_clb:
Radek Krejci3b1f9292018-11-08 10:58:35 +0100868 if (ctx->ctx->imp_clb) {
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100869 if (ctx->ctx->imp_clb(mod->mod->name, NULL, inc->name, inc->rev[0] ? inc->rev : NULL, ctx->ctx->imp_clb_data,
Radek Krejcibbe09a92018-11-08 09:36:54 +0100870 &format, &submodule_data, &submodule_data_free) == LY_SUCCESS) {
871 check_data.name = inc->name;
872 check_data.revision = inc->rev[0] ? inc->rev : NULL;
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100873 check_data.submoduleof = mod->mod->name;
874 submod = lys_parse_mem_submodule(ctx->ctx, submodule_data, format, ctx,
875 lysp_load_module_check, &check_data);
Radek Krejcibbe09a92018-11-08 09:36:54 +0100876 if (submodule_data_free) {
Radek Krejci3b1f9292018-11-08 10:58:35 +0100877 submodule_data_free((void*)submodule_data, ctx->ctx->imp_clb_data);
Radek Krejcid33273d2018-10-25 14:55:52 +0200878 }
879 }
Radek Krejcid33273d2018-10-25 14:55:52 +0200880 }
Radek Krejci3b1f9292018-11-08 10:58:35 +0100881 if (!submod && !(ctx->ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
Radek Krejcibbe09a92018-11-08 09:36:54 +0100882 goto search_file;
Radek Krejcid33273d2018-10-25 14:55:52 +0200883 }
Radek Krejci2d31ea72018-10-25 15:46:42 +0200884 } else {
Radek Krejcibbe09a92018-11-08 09:36:54 +0100885search_file:
Radek Krejci3b1f9292018-11-08 10:58:35 +0100886 if (!(ctx->ctx->flags & LY_CTX_DISABLE_SEARCHDIRS)) {
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100887 /* submodule was not received from the callback or there is no callback set */
888 lys_module_localfile(ctx->ctx, inc->name, inc->rev[0] ? inc->rev : NULL, 0, ctx, (void**)&submod);
Radek Krejcibbe09a92018-11-08 09:36:54 +0100889 }
Radek Krejci3b1f9292018-11-08 10:58:35 +0100890 if (!submod && (ctx->ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
Radek Krejcibbe09a92018-11-08 09:36:54 +0100891 goto search_clb;
892 }
893 }
894 if (submod) {
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100895 if (!inc->rev[0] && (submod->latest_revision == 1)) {
Radek Krejcibbe09a92018-11-08 09:36:54 +0100896 /* update the latest_revision flag - here we have selected the latest available schema,
897 * consider that even the callback provides correct latest revision */
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100898 submod->latest_revision = 2;
Radek Krejcibbe09a92018-11-08 09:36:54 +0100899 }
900
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100901 inc->submodule = submod;
Radek Krejcid33273d2018-10-25 14:55:52 +0200902 }
903 if (!inc->submodule) {
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100904 LOGVAL(ctx->ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE, "Including \"%s\" submodule into \"%s\" failed.",
905 inc->name, mod->mod->name);
Radek Krejcid33273d2018-10-25 14:55:52 +0200906 return LY_EVALID;
907 }
908
909 return LY_SUCCESS;
910}
911
Radek Krejci01342af2019-01-03 15:18:08 +0100912#define FIND_MODULE(TYPE, MOD) \
Radek Krejcice8c1592018-10-29 15:35:51 +0100913 TYPE *imp; \
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100914 if (!strncmp((MOD)->mod->prefix, prefix, len) && (MOD)->mod->prefix[len] == '\0') { \
Radek Krejcice8c1592018-10-29 15:35:51 +0100915 /* it is the prefix of the module itself */ \
Radek Krejci0af46292019-01-11 16:02:31 +0100916 m = ly_ctx_get_module((MOD)->mod->ctx, (MOD)->mod->name, (MOD)->mod->revision); \
Radek Krejcice8c1592018-10-29 15:35:51 +0100917 } \
918 /* search in imports */ \
Radek Krejcibbe09a92018-11-08 09:36:54 +0100919 if (!m) { \
920 LY_ARRAY_FOR((MOD)->imports, TYPE, imp) { \
Radek Krejci01342af2019-01-03 15:18:08 +0100921 if (!strncmp(imp->prefix, prefix, len) && imp->prefix[len] == '\0') { \
Radek Krejcibbe09a92018-11-08 09:36:54 +0100922 m = imp->module; \
923 break; \
924 } \
Radek Krejcice8c1592018-10-29 15:35:51 +0100925 } \
Radek Krejcibbe09a92018-11-08 09:36:54 +0100926 }
Radek Krejcice8c1592018-10-29 15:35:51 +0100927
Radek Krejcibbe09a92018-11-08 09:36:54 +0100928struct lysc_module *
Radek Krejcia3045382018-11-22 14:30:31 +0100929lysc_module_find_prefix(const struct lysc_module *mod, const char *prefix, size_t len)
Radek Krejci151a5b72018-10-19 14:21:44 +0200930{
Radek Krejcibbe09a92018-11-08 09:36:54 +0100931 const struct lys_module *m = NULL;
932
Radek Krejci01342af2019-01-03 15:18:08 +0100933 FIND_MODULE(struct lysc_import, mod);
Radek Krejcibbe09a92018-11-08 09:36:54 +0100934 return m ? m->compiled : NULL;
Radek Krejcice8c1592018-10-29 15:35:51 +0100935}
Radek Krejci151a5b72018-10-19 14:21:44 +0200936
Radek Krejcibbe09a92018-11-08 09:36:54 +0100937struct lysp_module *
Radek Krejcia3045382018-11-22 14:30:31 +0100938lysp_module_find_prefix(const struct lysp_module *mod, const char *prefix, size_t len)
Radek Krejcice8c1592018-10-29 15:35:51 +0100939{
Radek Krejcibbe09a92018-11-08 09:36:54 +0100940 const struct lys_module *m = NULL;
941
Radek Krejci01342af2019-01-03 15:18:08 +0100942 FIND_MODULE(struct lysp_import, mod);
Radek Krejcibbe09a92018-11-08 09:36:54 +0100943 return m ? m->parsed : NULL;
Radek Krejcice8c1592018-10-29 15:35:51 +0100944}
Radek Krejci151a5b72018-10-19 14:21:44 +0200945
Radek Krejcice8c1592018-10-29 15:35:51 +0100946struct lys_module *
Radek Krejcia3045382018-11-22 14:30:31 +0100947lys_module_find_prefix(const struct lys_module *mod, const char *prefix, size_t len)
Radek Krejcice8c1592018-10-29 15:35:51 +0100948{
Radek Krejcibbe09a92018-11-08 09:36:54 +0100949 const struct lys_module *m = NULL;
950
Radek Krejcice8c1592018-10-29 15:35:51 +0100951 if (mod->compiled) {
Radek Krejci01342af2019-01-03 15:18:08 +0100952 FIND_MODULE(struct lysc_import, mod->compiled);
Radek Krejcice8c1592018-10-29 15:35:51 +0100953 } else {
Radek Krejci01342af2019-01-03 15:18:08 +0100954 FIND_MODULE(struct lysp_import, mod->parsed);
Radek Krejcibbe09a92018-11-08 09:36:54 +0100955 }
956 return (struct lys_module*)m;
957}
958
Radek Krejcia3045382018-11-22 14:30:31 +0100959const char *
Radek Krejci693262f2019-04-29 15:23:20 +0200960lys_prefix_find_module(const struct lys_module *mod, const struct lys_module *import)
961{
962 unsigned int u;
963
964 if (import == mod) {
965 return mod->prefix;
966 }
967
968 if (mod->parsed) {
969 LY_ARRAY_FOR(mod->parsed->imports, u) {
970 if (mod->parsed->imports[u].module == import) {
971 return mod->parsed->imports[u].prefix;
972 }
973 }
974 } else {
975 /* we don't have original information about the import's prefix,
976 * so the prefix of the import module itself is returned instead */
977 return import->prefix;
978 }
979
980 return NULL;
981}
982
983const char *
Radek Krejcia3045382018-11-22 14:30:31 +0100984lys_nodetype2str(uint16_t nodetype)
985{
986 switch(nodetype) {
987 case LYS_CONTAINER:
988 return "container";
989 case LYS_CHOICE:
990 return "choice";
991 case LYS_LEAF:
992 return "leaf";
993 case LYS_LEAFLIST:
994 return "leaf-list";
995 case LYS_LIST:
996 return "list";
997 case LYS_ANYXML:
998 return "anyxml";
999 case LYS_ANYDATA:
1000 return "anydata";
Radek Krejcif12a1f02019-02-11 16:42:08 +01001001 case LYS_CASE:
1002 return "case";
Radek Krejcif538ce52019-03-05 10:46:14 +01001003 case LYS_ACTION:
1004 return "RPC/action";
1005 case LYS_NOTIF:
1006 return "Notification";
Radek Krejcifc81ea82019-04-18 13:27:22 +02001007 case LYS_USES:
1008 return "uses";
Radek Krejcia3045382018-11-22 14:30:31 +01001009 default:
1010 return "unknown";
1011 }
1012}
1013
Radek Krejci693262f2019-04-29 15:23:20 +02001014const char *
1015lys_datatype2str(LY_DATA_TYPE basetype)
1016{
1017 switch(basetype) {
1018 case LY_TYPE_BINARY:
1019 return "binary";
1020 case LY_TYPE_UINT8:
1021 return "uint8";
1022 case LY_TYPE_UINT16:
1023 return "uint16";
1024 case LY_TYPE_UINT32:
1025 return "uint32";
1026 case LY_TYPE_UINT64:
1027 return "uint64";
1028 case LY_TYPE_STRING:
1029 return "string";
1030 case LY_TYPE_BITS:
1031 return "bits";
1032 case LY_TYPE_BOOL:
1033 return "boolean";
1034 case LY_TYPE_DEC64:
1035 return "decimal64";
1036 case LY_TYPE_EMPTY:
1037 return "empty";
1038 case LY_TYPE_ENUM:
1039 return "enumeration";
1040 case LY_TYPE_IDENT:
1041 return "identityref";
1042 case LY_TYPE_INST:
1043 return "instance-identifier";
1044 case LY_TYPE_LEAFREF:
1045 return "leafref";
1046 case LY_TYPE_UNION:
1047 return "union";
1048 case LY_TYPE_INT8:
1049 return "int8";
1050 case LY_TYPE_INT16:
1051 return "int16";
1052 case LY_TYPE_INT32:
1053 return "int32";
1054 case LY_TYPE_INT64:
1055 return "int64";
1056 default:
1057 return "unknown";
1058 }
1059}
1060
Radek Krejci056d0a82018-12-06 16:57:25 +01001061API const struct lysp_tpdf *
1062lysp_node_typedefs(const struct lysp_node *node)
1063{
Radek Krejci0fb28562018-12-13 15:17:37 +01001064 switch (node->nodetype) {
1065 case LYS_CONTAINER:
1066 return ((struct lysp_node_container*)node)->typedefs;
1067 case LYS_LIST:
1068 return ((struct lysp_node_list*)node)->typedefs;
1069 case LYS_GROUPING:
1070 return ((struct lysp_grp*)node)->typedefs;
1071 case LYS_ACTION:
1072 return ((struct lysp_action*)node)->typedefs;
1073 case LYS_INOUT:
1074 return ((struct lysp_action_inout*)node)->typedefs;
1075 case LYS_NOTIF:
1076 return ((struct lysp_notif*)node)->typedefs;
1077 default:
Radek Krejci056d0a82018-12-06 16:57:25 +01001078 return NULL;
1079 }
1080}
1081
Radek Krejci53ea6152018-12-13 15:21:15 +01001082API const struct lysp_grp *
1083lysp_node_groupings(const struct lysp_node *node)
1084{
1085 switch (node->nodetype) {
1086 case LYS_CONTAINER:
1087 return ((struct lysp_node_container*)node)->groupings;
1088 case LYS_LIST:
1089 return ((struct lysp_node_list*)node)->groupings;
1090 case LYS_GROUPING:
1091 return ((struct lysp_grp*)node)->groupings;
1092 case LYS_ACTION:
1093 return ((struct lysp_action*)node)->groupings;
1094 case LYS_INOUT:
1095 return ((struct lysp_action_inout*)node)->groupings;
1096 case LYS_NOTIF:
1097 return ((struct lysp_notif*)node)->groupings;
1098 default:
1099 return NULL;
1100 }
1101}
1102
Radek Krejcibbe09a92018-11-08 09:36:54 +01001103struct lysp_action **
Radek Krejci056d0a82018-12-06 16:57:25 +01001104lysp_node_actions_p(struct lysp_node *node)
Radek Krejcibbe09a92018-11-08 09:36:54 +01001105{
1106 assert(node);
1107 switch (node->nodetype) {
1108 case LYS_CONTAINER:
1109 return &((struct lysp_node_container*)node)->actions;
1110 case LYS_LIST:
1111 return &((struct lysp_node_list*)node)->actions;
1112 case LYS_GROUPING:
1113 return &((struct lysp_grp*)node)->actions;
1114 case LYS_AUGMENT:
1115 return &((struct lysp_augment*)node)->actions;
1116 default:
1117 return NULL;
1118 }
1119}
1120
Radek Krejci056d0a82018-12-06 16:57:25 +01001121API const struct lysp_action *
1122lysp_node_actions(const struct lysp_node *node)
1123{
1124 struct lysp_action **actions;
1125 actions = lysp_node_actions_p((struct lysp_node*)node);
1126 if (actions) {
1127 return *actions;
1128 } else {
1129 return NULL;
1130 }
1131}
1132
Radek Krejcibbe09a92018-11-08 09:36:54 +01001133struct lysp_notif **
Radek Krejci056d0a82018-12-06 16:57:25 +01001134lysp_node_notifs_p(struct lysp_node *node)
Radek Krejcibbe09a92018-11-08 09:36:54 +01001135{
1136 assert(node);
1137 switch (node->nodetype) {
1138 case LYS_CONTAINER:
1139 return &((struct lysp_node_container*)node)->notifs;
1140 case LYS_LIST:
1141 return &((struct lysp_node_list*)node)->notifs;
1142 case LYS_GROUPING:
1143 return &((struct lysp_grp*)node)->notifs;
1144 case LYS_AUGMENT:
1145 return &((struct lysp_augment*)node)->notifs;
1146 default:
1147 return NULL;
1148 }
1149}
1150
Radek Krejci056d0a82018-12-06 16:57:25 +01001151API const struct lysp_notif *
1152lysp_node_notifs(const struct lysp_node *node)
1153{
1154 struct lysp_notif **notifs;
1155 notifs = lysp_node_notifs_p((struct lysp_node*)node);
1156 if (notifs) {
1157 return *notifs;
1158 } else {
1159 return NULL;
1160 }
1161}
1162
Radek Krejcibbe09a92018-11-08 09:36:54 +01001163struct lysp_node **
Radek Krejci056d0a82018-12-06 16:57:25 +01001164lysp_node_children_p(struct lysp_node *node)
Radek Krejcibbe09a92018-11-08 09:36:54 +01001165{
1166 assert(node);
1167 switch (node->nodetype) {
1168 case LYS_CONTAINER:
1169 return &((struct lysp_node_container*)node)->child;
1170 case LYS_CHOICE:
1171 return &((struct lysp_node_choice*)node)->child;
1172 case LYS_LIST:
1173 return &((struct lysp_node_list*)node)->child;
1174 case LYS_CASE:
1175 return &((struct lysp_node_case*)node)->child;
1176 case LYS_GROUPING:
1177 return &((struct lysp_grp*)node)->data;
1178 case LYS_AUGMENT:
1179 return &((struct lysp_augment*)node)->child;
1180 case LYS_INOUT:
1181 return &((struct lysp_action_inout*)node)->data;
1182 case LYS_NOTIF:
1183 return &((struct lysp_notif*)node)->data;
1184 default:
1185 return NULL;
1186 }
1187}
1188
Radek Krejci056d0a82018-12-06 16:57:25 +01001189API const struct lysp_node *
1190lysp_node_children(const struct lysp_node *node)
1191{
1192 struct lysp_node **children;
Radek Krejcie7b95092019-05-15 11:03:07 +02001193
1194 if (!node) {
1195 return NULL;
1196 }
1197
Radek Krejci056d0a82018-12-06 16:57:25 +01001198 children = lysp_node_children_p((struct lysp_node*)node);
1199 if (children) {
1200 return *children;
1201 } else {
1202 return NULL;
1203 }
1204}
1205
1206struct lysc_action **
1207lysc_node_actions_p(struct lysc_node *node)
1208{
1209 assert(node);
1210 switch (node->nodetype) {
1211 case LYS_CONTAINER:
1212 return &((struct lysc_node_container*)node)->actions;
1213 case LYS_LIST:
1214 return &((struct lysc_node_list*)node)->actions;
1215 default:
1216 return NULL;
1217 }
1218}
1219
1220API const struct lysc_action *
1221lysc_node_actions(const struct lysc_node *node)
1222{
1223 struct lysc_action **actions;
1224 actions = lysc_node_actions_p((struct lysc_node*)node);
1225 if (actions) {
1226 return *actions;
1227 } else {
1228 return NULL;
1229 }
1230}
1231
1232struct lysc_notif **
1233lysc_node_notifs_p(struct lysc_node *node)
1234{
1235 assert(node);
1236 switch (node->nodetype) {
1237 case LYS_CONTAINER:
1238 return &((struct lysc_node_container*)node)->notifs;
1239 case LYS_LIST:
1240 return &((struct lysc_node_list*)node)->notifs;
1241 default:
1242 return NULL;
1243 }
1244}
1245
1246API const struct lysc_notif *
1247lysc_node_notifs(const struct lysc_node *node)
1248{
1249 struct lysc_notif **notifs;
1250 notifs = lysc_node_notifs_p((struct lysc_node*)node);
1251 if (notifs) {
1252 return *notifs;
1253 } else {
1254 return NULL;
1255 }
1256}
1257
Radek Krejcibbe09a92018-11-08 09:36:54 +01001258struct lysc_node **
Radek Krejci6eeb58f2019-02-22 16:29:37 +01001259lysc_node_children_p(const struct lysc_node *node, uint16_t flags)
Radek Krejcibbe09a92018-11-08 09:36:54 +01001260{
1261 assert(node);
1262 switch (node->nodetype) {
1263 case LYS_CONTAINER:
1264 return &((struct lysc_node_container*)node)->child;
1265 case LYS_CHOICE:
Radek Krejcia3045382018-11-22 14:30:31 +01001266 if (((struct lysc_node_choice*)node)->cases) {
Radek Krejci95710c92019-02-11 15:49:55 +01001267 return &((struct lysc_node_choice*)node)->cases->child;
Radek Krejcia3045382018-11-22 14:30:31 +01001268 } else {
1269 return NULL;
1270 }
Radek Krejci01342af2019-01-03 15:18:08 +01001271 case LYS_CASE:
1272 return &((struct lysc_node_case*)node)->child;
Radek Krejcibbe09a92018-11-08 09:36:54 +01001273 case LYS_LIST:
1274 return &((struct lysc_node_list*)node)->child;
Radek Krejci6eeb58f2019-02-22 16:29:37 +01001275 case LYS_ACTION:
1276 if (flags & LYS_CONFIG_R) {
1277 return &((struct lysc_action*)node)->output.data;
1278 } else {
1279 /* LYS_CONFIG_W, but also the default case */
1280 return &((struct lysc_action*)node)->input.data;
1281 }
Radek Krejcifc11bd72019-04-11 16:00:05 +02001282 case LYS_NOTIF:
1283 return &((struct lysc_notif*)node)->data;
Radek Krejcibbe09a92018-11-08 09:36:54 +01001284 default:
1285 return NULL;
1286 }
1287}
1288
Radek Krejci056d0a82018-12-06 16:57:25 +01001289API const struct lysc_node *
Radek Krejci6eeb58f2019-02-22 16:29:37 +01001290lysc_node_children(const struct lysc_node *node, uint16_t flags)
Radek Krejcia3045382018-11-22 14:30:31 +01001291{
Radek Krejci056d0a82018-12-06 16:57:25 +01001292 struct lysc_node **children;
Radek Krejcie7b95092019-05-15 11:03:07 +02001293
1294 if (!node) {
1295 return NULL;
1296 }
1297
Radek Krejci6eeb58f2019-02-22 16:29:37 +01001298 children = lysc_node_children_p((struct lysc_node*)node, flags);
Radek Krejci056d0a82018-12-06 16:57:25 +01001299 if (children) {
1300 return *children;
1301 } else {
Radek Krejcia3045382018-11-22 14:30:31 +01001302 return NULL;
1303 }
1304}
1305
Radek Krejci96a0bfd2018-11-22 15:25:06 +01001306struct lys_module *
1307lysp_find_module(struct ly_ctx *ctx, const struct lysp_module *mod)
1308{
1309 unsigned int u;
1310
1311 for (u = 0; u < ctx->list.count; ++u) {
1312 if (((struct lys_module*)ctx->list.objs[u])->parsed == mod) {
1313 return ((struct lys_module*)ctx->list.objs[u]);
1314 }
1315 }
1316 return NULL;
1317}
1318
Radek Krejcid3ca0632019-04-16 16:54:54 +02001319unsigned int
1320lysp_ext_instance_iter(struct lysp_ext_instance *ext, unsigned int index, LYEXT_SUBSTMT substmt)
1321{
1322 LY_CHECK_ARG_RET(NULL, ext, LY_EINVAL);
1323
1324 for (; index < LY_ARRAY_SIZE(ext); index++) {
1325 if (ext[index].insubstmt == substmt) {
1326 return index;
1327 }
1328 }
1329
1330 return LY_ARRAY_SIZE(ext);
1331}
1332
1333