blob: f38aeec6d2391ae8cfed4d18625c9872cd5d6084 [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>
Radek Krejci86d106e2018-10-18 09:53:19 +020017#include <ctype.h>
Radek Krejci9ed7a192018-10-31 16:23:51 +010018#include <errno.h>
19#include <fcntl.h>
Radek Krejci86d106e2018-10-18 09:53:19 +020020#include <limits.h>
Radek Krejcie7b95092019-05-15 11:03:07 +020021#include <stdint.h>
Radek Krejci9ed7a192018-10-31 16:23:51 +010022#include <stdlib.h>
Radek Krejcie7b95092019-05-15 11:03:07 +020023#include <string.h>
Radek Krejci9ed7a192018-10-31 16:23:51 +010024#include <unistd.h>
Radek Krejci86d106e2018-10-18 09:53:19 +020025#include <time.h>
26
Radek Krejcie7b95092019-05-15 11:03:07 +020027#include "context.h"
28#include "dict.h"
29#include "extensions.h"
30#include "hash_table.h"
31#include "log.h"
32#include "set.h"
33#include "tree.h"
34#include "tree_schema.h"
Radek Krejci86d106e2018-10-18 09:53:19 +020035#include "tree_schema_internal.h"
36
Radek Krejcia3045382018-11-22 14:30:31 +010037/**
38 * @brief Parse an identifier.
39 *
40 * ;; An identifier MUST NOT start with (('X'|'x') ('M'|'m') ('L'|'l'))
41 * identifier = (ALPHA / "_")
42 * *(ALPHA / DIGIT / "_" / "-" / ".")
43 *
44 * @param[in,out] id Identifier to parse. When returned, it points to the first character which is not part of the identifier.
45 * @return LY_ERR value: LY_SUCCESS or LY_EINVAL in case of invalid starting character.
46 */
47static LY_ERR
48lys_parse_id(const char **id)
49{
50 assert(id && *id);
51
Radek Krejcia9026eb2018-12-12 16:04:47 +010052 if (!is_yangidentstartchar(**id)) {
Radek Krejcia3045382018-11-22 14:30:31 +010053 return LY_EINVAL;
54 }
55 ++(*id);
56
Radek Krejcia9026eb2018-12-12 16:04:47 +010057 while (is_yangidentchar(**id)) {
Radek Krejcia3045382018-11-22 14:30:31 +010058 ++(*id);
59 }
60 return LY_SUCCESS;
61}
62
63LY_ERR
64lys_parse_nodeid(const char **id, const char **prefix, size_t *prefix_len, const char **name, size_t *name_len)
65{
66 assert(id && *id);
67 assert(prefix && prefix_len);
68 assert(name && name_len);
69
70 *prefix = *id;
71 *prefix_len = 0;
72 *name = NULL;
73 *name_len = 0;
74
75 LY_CHECK_RET(lys_parse_id(id));
76 if (**id == ':') {
77 /* there is prefix */
78 *prefix_len = *id - *prefix;
79 ++(*id);
80 *name = *id;
81
82 LY_CHECK_RET(lys_parse_id(id));
83 *name_len = *id - *name;
84 } else {
85 /* there is no prefix, so what we have as prefix now is actually the name */
86 *name = *prefix;
87 *name_len = *id - *name;
88 *prefix = NULL;
89 }
90
91 return LY_SUCCESS;
92}
93
Radek Krejci86d106e2018-10-18 09:53:19 +020094LY_ERR
Radek Krejci95710c92019-02-11 15:49:55 +010095lys_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 +010096 const struct lys_module *context_module, int nodetype, int implement,
97 const struct lysc_node **target, uint16_t *result_flag)
Radek Krejci9bb94eb2018-12-04 16:48:35 +010098{
99 LY_ERR ret = LY_EVALID;
100 const char *name, *prefix, *id;
Radek Krejci9bb94eb2018-12-04 16:48:35 +0100101 size_t name_len, prefix_len;
Radek Krejci7af64242019-02-18 13:07:53 +0100102 const struct lys_module *mod;
Radek Krejci95710c92019-02-11 15:49:55 +0100103 const char *nodeid_type;
Radek Krejci6eeb58f2019-02-22 16:29:37 +0100104 int getnext_extra_flag = 0;
Radek Krejci05b774b2019-02-25 13:26:18 +0100105 int current_nodetype = 0;
Radek Krejci9bb94eb2018-12-04 16:48:35 +0100106
107 assert(nodeid);
Radek Krejci9bb94eb2018-12-04 16:48:35 +0100108 assert(target);
Radek Krejci6eeb58f2019-02-22 16:29:37 +0100109 assert(result_flag);
Radek Krejci9bb94eb2018-12-04 16:48:35 +0100110 *target = NULL;
Radek Krejci6eeb58f2019-02-22 16:29:37 +0100111 *result_flag = 0;
Radek Krejci9bb94eb2018-12-04 16:48:35 +0100112
113 id = nodeid;
Radek Krejci95710c92019-02-11 15:49:55 +0100114
115 if (context_node) {
116 /* descendant-schema-nodeid */
117 nodeid_type = "descendant";
Radek Krejci3641f562019-02-13 15:38:40 +0100118
119 if (*id == '/') {
120 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
121 "Invalid descendant-schema-nodeid value \"%.*s\" - absolute-schema-nodeid used.",
122 nodeid_len ? nodeid_len : strlen(nodeid), nodeid);
123 return LY_EVALID;
124 }
Radek Krejci95710c92019-02-11 15:49:55 +0100125 } else {
126 /* absolute-schema-nodeid */
127 nodeid_type = "absolute";
Radek Krejci95710c92019-02-11 15:49:55 +0100128
129 if (*id != '/') {
130 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
131 "Invalid absolute-schema-nodeid value \"%.*s\" - missing starting \"/\".",
Radek Krejci3641f562019-02-13 15:38:40 +0100132 nodeid_len ? nodeid_len : strlen(nodeid), nodeid);
Radek Krejci95710c92019-02-11 15:49:55 +0100133 return LY_EVALID;
134 }
135 ++id;
136 }
137
Radek Krejci9bb94eb2018-12-04 16:48:35 +0100138 while (*id && (ret = lys_parse_nodeid(&id, &prefix, &prefix_len, &name, &name_len)) == LY_SUCCESS) {
139 if (prefix) {
Radek Krejci95710c92019-02-11 15:49:55 +0100140 mod = lys_module_find_prefix(context_module, prefix, prefix_len);
Radek Krejci9bb94eb2018-12-04 16:48:35 +0100141 if (!mod) {
142 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
Radek Krejci95710c92019-02-11 15:49:55 +0100143 "Invalid %s-schema-nodeid value \"%.*s\" - prefix \"%.*s\" not defined in module \"%s\".",
144 nodeid_type, id - nodeid, nodeid, prefix_len, prefix, context_module->name);
Radek Krejci9bb94eb2018-12-04 16:48:35 +0100145 return LY_ENOTFOUND;
146 }
147 } else {
Radek Krejci95710c92019-02-11 15:49:55 +0100148 mod = context_module;
149 }
150 if (implement && !mod->implemented) {
151 /* make the module implemented */
152 ly_ctx_module_implement_internal(ctx->ctx, (struct lys_module*)mod, 2);
Radek Krejci9bb94eb2018-12-04 16:48:35 +0100153 }
Radek Krejci6eeb58f2019-02-22 16:29:37 +0100154 if (context_node && context_node->nodetype == LYS_ACTION) {
155 /* move through input/output manually */
156 if (!strncmp("input", name, name_len)) {
157 (*result_flag) |= LYSC_OPT_RPC_INPUT;
Radek Krejci05b774b2019-02-25 13:26:18 +0100158 } else if (!strncmp("output", name, name_len)) {
Radek Krejci6eeb58f2019-02-22 16:29:37 +0100159 (*result_flag) |= LYSC_OPT_RPC_OUTPUT;
160 getnext_extra_flag = LYS_GETNEXT_OUTPUT;
Radek Krejci05b774b2019-02-25 13:26:18 +0100161 } else {
162 goto getnext;
Radek Krejci6eeb58f2019-02-22 16:29:37 +0100163 }
Radek Krejci05b774b2019-02-25 13:26:18 +0100164 current_nodetype = LYS_INOUT;
Radek Krejci6eeb58f2019-02-22 16:29:37 +0100165 } else {
Radek Krejci05b774b2019-02-25 13:26:18 +0100166getnext:
Radek Krejci6eeb58f2019-02-22 16:29:37 +0100167 context_node = lys_child(context_node, mod, name, name_len, 0,
168 getnext_extra_flag | LYS_GETNEXT_NOSTATECHECK | LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE);
169 if (!context_node) {
170 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
171 "Invalid %s-schema-nodeid value \"%.*s\" - target node not found.", nodeid_type, id - nodeid, nodeid);
172 return LY_ENOTFOUND;
173 }
174 getnext_extra_flag = 0;
Radek Krejci05b774b2019-02-25 13:26:18 +0100175 current_nodetype = context_node->nodetype;
Radek Krejci6eeb58f2019-02-22 16:29:37 +0100176
Radek Krejci05b774b2019-02-25 13:26:18 +0100177 if (current_nodetype == LYS_NOTIF) {
Radek Krejci6eeb58f2019-02-22 16:29:37 +0100178 (*result_flag) |= LYSC_OPT_NOTIFICATION;
179 }
Radek Krejci9bb94eb2018-12-04 16:48:35 +0100180 }
Radek Krejci01342af2019-01-03 15:18:08 +0100181 if (!*id || (nodeid_len && ((size_t)(id - nodeid) >= nodeid_len))) {
Radek Krejci9bb94eb2018-12-04 16:48:35 +0100182 break;
183 }
Radek Krejci01342af2019-01-03 15:18:08 +0100184 if (*id != '/') {
Radek Krejci9bb94eb2018-12-04 16:48:35 +0100185 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
Radek Krejci95710c92019-02-11 15:49:55 +0100186 "Invalid %s-schema-nodeid value \"%.*s\" - missing \"/\" as node-identifier separator.",
187 nodeid_type, id - nodeid + 1, nodeid);
Radek Krejci9bb94eb2018-12-04 16:48:35 +0100188 return LY_EVALID;
189 }
190 ++id;
191 }
192
193 if (ret == LY_SUCCESS) {
Radek Krejci7af64242019-02-18 13:07:53 +0100194 *target = context_node;
Radek Krejci05b774b2019-02-25 13:26:18 +0100195 if (nodetype & LYS_INOUT) {
196 /* instead of input/output nodes, the RPC/action node is actually returned */
197 }
198 if (nodetype && !(current_nodetype & nodetype)) {
Radek Krejci9bb94eb2018-12-04 16:48:35 +0100199 return LY_EDENIED;
200 }
Radek Krejci95710c92019-02-11 15:49:55 +0100201 } else {
202 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
203 "Invalid %s-schema-nodeid value \"%.*s\" - unexpected end of expression.",
Radek Krejci3641f562019-02-13 15:38:40 +0100204 nodeid_type, nodeid_len ? nodeid_len : strlen(nodeid), nodeid);
Radek Krejci9bb94eb2018-12-04 16:48:35 +0100205 }
206
207 return ret;
208}
209
210LY_ERR
Radek Krejcie7b95092019-05-15 11:03:07 +0200211lysp_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 +0200212{
213 struct lysp_import *i;
214
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100215 if (module_prefix && &module_prefix != value && !strcmp(module_prefix, *value)) {
Radek Krejci86d106e2018-10-18 09:53:19 +0200216 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_REFERENCE,
217 "Prefix \"%s\" already used as module prefix.", *value);
218 return LY_EEXIST;
219 }
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100220 LY_ARRAY_FOR(imports, struct lysp_import, i) {
221 if (i->prefix && &i->prefix != value && !strcmp(i->prefix, *value)) {
222 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_REFERENCE, "Prefix \"%s\" already used to import \"%s\" module.",
223 *value, i->name);
224 return LY_EEXIST;
Radek Krejci86d106e2018-10-18 09:53:19 +0200225 }
226 }
227 return LY_SUCCESS;
228}
229
230LY_ERR
Radek Krejci4f28eda2018-11-12 11:46:16 +0100231lysc_check_status(struct lysc_ctx *ctx,
232 uint16_t flags1, void *mod1, const char *name1,
233 uint16_t flags2, void *mod2, const char *name2)
234{
235 uint16_t flg1, flg2;
236
237 flg1 = (flags1 & LYS_STATUS_MASK) ? (flags1 & LYS_STATUS_MASK) : LYS_STATUS_CURR;
238 flg2 = (flags2 & LYS_STATUS_MASK) ? (flags2 & LYS_STATUS_MASK) : LYS_STATUS_CURR;
239
240 if ((flg1 < flg2) && (mod1 == mod2)) {
241 if (ctx) {
242 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
243 "A %s definition \"%s\" is not allowed to reference %s definition \"%s\".",
244 flg1 == LYS_STATUS_CURR ? "current" : "deprecated", name1,
245 flg2 == LYS_STATUS_OBSLT ? "obsolete" : "deprecated", name2);
246 }
247 return LY_EVALID;
248 }
249
250 return LY_SUCCESS;
251}
252
253LY_ERR
Radek Krejcie7b95092019-05-15 11:03:07 +0200254lysp_check_date(struct lys_parser_ctx *ctx, const char *date, int date_len, const char *stmt)
Radek Krejci86d106e2018-10-18 09:53:19 +0200255{
256 int i;
257 struct tm tm, tm_;
258 char *r;
259
Radek Krejcibbe09a92018-11-08 09:36:54 +0100260 LY_CHECK_ARG_RET(ctx ? ctx->ctx : NULL, date, LY_EINVAL);
261 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 +0200262
263 /* check format */
264 for (i = 0; i < date_len; i++) {
265 if (i == 4 || i == 7) {
266 if (date[i] != '-') {
267 goto error;
268 }
269 } else if (!isdigit(date[i])) {
270 goto error;
271 }
272 }
273
274 /* check content, e.g. 2018-02-31 */
275 memset(&tm, 0, sizeof tm);
276 r = strptime(date, "%Y-%m-%d", &tm);
277 if (!r || r != &date[LY_REV_SIZE - 1]) {
278 goto error;
279 }
280 memcpy(&tm_, &tm, sizeof tm);
281 mktime(&tm_); /* mktime modifies tm_ if it refers invalid date */
282 if (tm.tm_mday != tm_.tm_mday) { /* e.g 2018-02-29 -> 2018-03-01 */
283 /* checking days is enough, since other errors
284 * have been checked by strptime() */
285 goto error;
286 }
287
288 return LY_SUCCESS;
289
290error:
Radek Krejcid33273d2018-10-25 14:55:52 +0200291 if (stmt) {
Radek Krejcibbe09a92018-11-08 09:36:54 +0100292 if (ctx) {
293 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LY_VCODE_INVAL, date_len, date, stmt);
294 } else {
295 LOGVAL(NULL, LY_VLOG_NONE, NULL, LY_VCODE_INVAL, date_len, date, stmt);
296 }
Radek Krejcid33273d2018-10-25 14:55:52 +0200297 }
Radek Krejci86d106e2018-10-18 09:53:19 +0200298 return LY_EINVAL;
299}
300
301void
302lysp_sort_revisions(struct lysp_revision *revs)
303{
304 uint8_t i, r;
305 struct lysp_revision rev;
306
307 for (i = 1, r = 0; revs && i < LY_ARRAY_SIZE(revs); i++) {
Radek Krejcib7db73a2018-10-24 14:18:40 +0200308 if (strcmp(revs[i].date, revs[r].date) > 0) {
Radek Krejci86d106e2018-10-18 09:53:19 +0200309 r = i;
310 }
311 }
312
313 if (r) {
314 /* the newest revision is not on position 0, switch them */
Radek Krejci2c4e7172018-10-19 15:56:26 +0200315 memcpy(&rev, &revs[0], sizeof rev);
316 memcpy(&revs[0], &revs[r], sizeof rev);
317 memcpy(&revs[r], &rev, sizeof rev);
Radek Krejci86d106e2018-10-18 09:53:19 +0200318 }
319}
Radek Krejci151a5b72018-10-19 14:21:44 +0200320
Radek Krejcibbe09a92018-11-08 09:36:54 +0100321static const struct lysp_tpdf *
322lysp_type_match(const char *name, struct lysp_node *node)
323{
Radek Krejci0fb28562018-12-13 15:17:37 +0100324 const struct lysp_tpdf *typedefs;
Radek Krejcibbe09a92018-11-08 09:36:54 +0100325 unsigned int u;
326
Radek Krejci0fb28562018-12-13 15:17:37 +0100327 typedefs = lysp_node_typedefs(node);
328 LY_ARRAY_FOR(typedefs, u) {
329 if (!strcmp(name, typedefs[u].name)) {
330 /* match */
331 return &typedefs[u];
Radek Krejcibbe09a92018-11-08 09:36:54 +0100332 }
333 }
334
335 return NULL;
336}
337
Radek Krejci4f28eda2018-11-12 11:46:16 +0100338static LY_DATA_TYPE
339lysp_type_str2builtin(const char *name, size_t len)
340{
341 if (len >= 4) { /* otherwise it does not match any built-in type */
342 if (name[0] == 'b') {
343 if (name[1] == 'i') {
344 if (len == 6 && !strncmp(&name[2], "nary", 4)) {
345 return LY_TYPE_BINARY;
346 } else if (len == 4 && !strncmp(&name[2], "ts", 2)) {
347 return LY_TYPE_BITS;
348 }
349 } else if (len == 7 && !strncmp(&name[1], "oolean", 6)) {
350 return LY_TYPE_BOOL;
351 }
352 } else if (name[0] == 'd') {
353 if (len == 9 && !strncmp(&name[1], "ecimal64", 8)) {
354 return LY_TYPE_DEC64;
355 }
356 } else if (name[0] == 'e') {
357 if (len == 5 && !strncmp(&name[1], "mpty", 4)) {
358 return LY_TYPE_EMPTY;
359 } else if (len == 11 && !strncmp(&name[1], "numeration", 10)) {
360 return LY_TYPE_ENUM;
361 }
362 } else if (name[0] == 'i') {
363 if (name[1] == 'n') {
364 if (len == 4 && !strncmp(&name[2], "t8", 2)) {
365 return LY_TYPE_INT8;
366 } else if (len == 5) {
367 if (!strncmp(&name[2], "t16", 3)) {
368 return LY_TYPE_INT16;
369 } else if (!strncmp(&name[2], "t32", 3)) {
370 return LY_TYPE_INT32;
371 } else if (!strncmp(&name[2], "t64", 3)) {
372 return LY_TYPE_INT64;
373 }
374 } else if (len == 19 && !strncmp(&name[2], "stance-identifier", 17)) {
375 return LY_TYPE_INST;
376 }
377 } else if (len == 11 && !strncmp(&name[1], "dentityref", 10)) {
378 return LY_TYPE_IDENT;
379 }
380 } else if (name[0] == 'l') {
381 if (len == 7 && !strncmp(&name[1], "eafref", 6)) {
382 return LY_TYPE_LEAFREF;
383 }
384 } else if (name[0] == 's') {
385 if (len == 6 && !strncmp(&name[1], "tring", 5)) {
386 return LY_TYPE_STRING;
387 }
388 } else if (name[0] == 'u') {
389 if (name[1] == 'n') {
390 if (len == 5 && !strncmp(&name[2], "ion", 3)) {
391 return LY_TYPE_UNION;
392 }
393 } else if (name[1] == 'i' && name[2] == 'n' && name[3] == 't') {
394 if (len == 5 && name[4] == '8') {
395 return LY_TYPE_UINT8;
396 } else if (len == 6) {
397 if (!strncmp(&name[4], "16", 2)) {
398 return LY_TYPE_UINT16;
399 } else if (!strncmp(&name[4], "32", 2)) {
400 return LY_TYPE_UINT32;
401 } else if (!strncmp(&name[4], "64", 2)) {
402 return LY_TYPE_UINT64;
403 }
404 }
405 }
406 }
407 }
408
409 return LY_TYPE_UNKNOWN;
410}
411
Radek Krejcibbe09a92018-11-08 09:36:54 +0100412LY_ERR
413lysp_type_find(const char *id, struct lysp_node *start_node, struct lysp_module *start_module,
Radek Krejci4f28eda2018-11-12 11:46:16 +0100414 LY_DATA_TYPE *type, const struct lysp_tpdf **tpdf, struct lysp_node **node, struct lysp_module **module)
Radek Krejcibbe09a92018-11-08 09:36:54 +0100415{
416 const char *str, *name;
417 struct lysp_tpdf *typedefs;
418 unsigned int u, v;
419
420 assert(id);
421 assert(start_module);
422 assert(tpdf);
423 assert(node);
424 assert(module);
425
Radek Krejci4f28eda2018-11-12 11:46:16 +0100426 *node = NULL;
Radek Krejcibbe09a92018-11-08 09:36:54 +0100427 str = strchr(id, ':');
428 if (str) {
429 *module = lysp_module_find_prefix(start_module, id, str - id);
430 name = str + 1;
Radek Krejci4f28eda2018-11-12 11:46:16 +0100431 *type = LY_TYPE_UNKNOWN;
Radek Krejcibbe09a92018-11-08 09:36:54 +0100432 } else {
433 *module = start_module;
434 name = id;
Radek Krejci4f28eda2018-11-12 11:46:16 +0100435
436 /* check for built-in types */
437 *type = lysp_type_str2builtin(name, strlen(name));
438 if (*type) {
439 *tpdf = NULL;
440 return LY_SUCCESS;
441 }
Radek Krejcibbe09a92018-11-08 09:36:54 +0100442 }
443 LY_CHECK_RET(!(*module), LY_ENOTFOUND);
444
445 if (start_node && *module == start_module) {
446 /* search typedefs in parent's nodes */
447 *node = start_node;
448 while (*node) {
449 *tpdf = lysp_type_match(name, *node);
450 if (*tpdf) {
451 /* match */
452 return LY_SUCCESS;
453 }
454 *node = (*node)->parent;
455 }
456 }
457
458 /* search in top-level typedefs */
459 if ((*module)->typedefs) {
460 LY_ARRAY_FOR((*module)->typedefs, u) {
461 if (!strcmp(name, (*module)->typedefs[u].name)) {
462 /* match */
463 *tpdf = &(*module)->typedefs[u];
464 return LY_SUCCESS;
465 }
466 }
467 }
468
469 /* search in submodules' typedefs */
470 LY_ARRAY_FOR((*module)->includes, u) {
471 typedefs = (*module)->includes[u].submodule->typedefs;
Radek Krejci76b3e962018-12-14 17:01:25 +0100472 LY_ARRAY_FOR(typedefs, v) {
473 if (!strcmp(name, typedefs[v].name)) {
474 /* match */
475 *tpdf = &typedefs[v];
476 return LY_SUCCESS;
Radek Krejcibbe09a92018-11-08 09:36:54 +0100477 }
478 }
479 }
480
481 return LY_ENOTFOUND;
482}
483
484/*
485 * @brief Check name of a new type to avoid name collisions.
486 *
487 * @param[in] ctx Parser context, module where the type is being defined is taken from here.
488 * @param[in] node Schema node where the type is being defined, NULL in case of a top-level typedef.
489 * @param[in] tpdf Typedef definition to check.
490 * @param[in,out] tpdfs_global Initialized hash table to store temporary data between calls. When the module's
491 * typedefs are checked, caller is supposed to free the table.
492 * @param[in,out] tpdfs_global Initialized hash table to store temporary data between calls. When the module's
493 * typedefs are checked, caller is supposed to free the table.
494 * @return LY_EEXIST in case of collision, LY_SUCCESS otherwise.
495 */
496static LY_ERR
Radek Krejcie7b95092019-05-15 11:03:07 +0200497lysp_check_typedef(struct lys_parser_ctx *ctx, struct lysp_node *node, const struct lysp_tpdf *tpdf,
Radek Krejcibbe09a92018-11-08 09:36:54 +0100498 struct hash_table *tpdfs_global, struct hash_table *tpdfs_scoped)
499{
500 struct lysp_node *parent;
501 uint32_t hash;
502 size_t name_len;
503 const char *name;
504 unsigned int u;
Radek Krejci0fb28562018-12-13 15:17:37 +0100505 const struct lysp_tpdf *typedefs;
Radek Krejcibbe09a92018-11-08 09:36:54 +0100506
507 assert(ctx);
508 assert(tpdf);
509
510 name = tpdf->name;
511 name_len = strlen(name);
512
Radek Krejci4f28eda2018-11-12 11:46:16 +0100513 if (lysp_type_str2builtin(name, name_len)) {
514 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_SYNTAX_YANG,
515 "Invalid name \"%s\" of typedef - name collision with a built-in type.", name);
516 return LY_EEXIST;
Radek Krejcibbe09a92018-11-08 09:36:54 +0100517 }
518
519 /* check locally scoped typedefs (avoid name shadowing) */
520 if (node) {
Radek Krejci0fb28562018-12-13 15:17:37 +0100521 typedefs = lysp_node_typedefs(node);
522 LY_ARRAY_FOR(typedefs, u) {
523 if (&typedefs[u] == tpdf) {
524 break;
525 }
526 if (!strcmp(name, typedefs[u].name)) {
527 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_SYNTAX_YANG,
528 "Invalid name \"%s\" of typedef - name collision with sibling type.", name);
529 return LY_EEXIST;
Radek Krejcibbe09a92018-11-08 09:36:54 +0100530 }
531 }
532 /* search typedefs in parent's nodes */
Radek Krejci87e78ca2019-05-02 09:51:29 +0200533 for (parent = node->parent; parent; parent = parent->parent) {
Radek Krejcibbe09a92018-11-08 09:36:54 +0100534 if (lysp_type_match(name, parent)) {
535 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_SYNTAX_YANG,
536 "Invalid name \"%s\" of typedef - name collision with another scoped type.", name);
537 return LY_EEXIST;
538 }
539 }
540 }
541
542 /* check collision with the top-level typedefs */
543 hash = dict_hash(name, name_len);
544 if (node) {
545 lyht_insert(tpdfs_scoped, &name, hash, NULL);
546 if (!lyht_find(tpdfs_global, &name, hash, NULL)) {
547 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_SYNTAX_YANG,
548 "Invalid name \"%s\" of typedef - scoped type collide with a top-level type.", name);
549 return LY_EEXIST;
550 }
551 } else {
552 if (lyht_insert(tpdfs_global, &name, hash, NULL)) {
553 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_SYNTAX_YANG,
554 "Invalid name \"%s\" of typedef - name collision with another top-level type.", name);
555 return LY_EEXIST;
556 }
Radek Krejci3b1f9292018-11-08 10:58:35 +0100557 /* it is not necessary to test collision with the scoped types - in lysp_check_typedefs, all the
558 * top-level typedefs are inserted into the tables before the scoped typedefs, so the collision
559 * is detected in the first branch few lines above */
Radek Krejcibbe09a92018-11-08 09:36:54 +0100560 }
561
562 return LY_SUCCESS;
563}
564
565static int
566lysp_id_cmp(void *val1, void *val2, int UNUSED(mod), void *UNUSED(cb_data))
567{
568 return !strcmp(val1, val2);
569}
570
571LY_ERR
Radek Krejcie7b95092019-05-15 11:03:07 +0200572lysp_check_typedefs(struct lys_parser_ctx *ctx, struct lysp_module *mod)
Radek Krejcibbe09a92018-11-08 09:36:54 +0100573{
574 struct hash_table *ids_global;
575 struct hash_table *ids_scoped;
Radek Krejci0fb28562018-12-13 15:17:37 +0100576 const struct lysp_tpdf *typedefs;
Radek Krejcibbe09a92018-11-08 09:36:54 +0100577 unsigned int i, u;
578 LY_ERR ret = LY_EVALID;
579
580 /* check name collisions - typedefs and groupings */
581 ids_global = lyht_new(8, sizeof(char*), lysp_id_cmp, NULL, 1);
582 ids_scoped = lyht_new(8, sizeof(char*), lysp_id_cmp, NULL, 1);
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100583 LY_ARRAY_FOR(mod->typedefs, i) {
584 if (lysp_check_typedef(ctx, NULL, &mod->typedefs[i], ids_global, ids_scoped)) {
Radek Krejcibbe09a92018-11-08 09:36:54 +0100585 goto cleanup;
586 }
587 }
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100588 LY_ARRAY_FOR(mod->includes, i) {
589 LY_ARRAY_FOR(mod->includes[i].submodule->typedefs, u) {
590 if (lysp_check_typedef(ctx, NULL, &mod->includes[i].submodule->typedefs[u], ids_global, ids_scoped)) {
Radek Krejci3b1f9292018-11-08 10:58:35 +0100591 goto cleanup;
592 }
593 }
594 }
Radek Krejcibbe09a92018-11-08 09:36:54 +0100595 for (u = 0; u < ctx->tpdfs_nodes.count; ++u) {
Radek Krejci0fb28562018-12-13 15:17:37 +0100596 typedefs = lysp_node_typedefs((struct lysp_node *)ctx->tpdfs_nodes.objs[u]);
597 LY_ARRAY_FOR(typedefs, i) {
598 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 +0100599 goto cleanup;
600 }
601 }
602 }
603 ret = LY_SUCCESS;
604cleanup:
605 lyht_free(ids_global);
606 lyht_free(ids_scoped);
607 ly_set_erase(&ctx->tpdfs_nodes, NULL);
608
609 return ret;
610}
611
Radek Krejci9ed7a192018-10-31 16:23:51 +0100612struct lysp_load_module_check_data {
613 const char *name;
614 const char *revision;
615 const char *path;
616 const char* submoduleof;
617};
618
619static LY_ERR
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100620lysp_load_module_check(struct ly_ctx *ctx, struct lysp_module *mod, struct lysp_submodule *submod, void *data)
Radek Krejci9ed7a192018-10-31 16:23:51 +0100621{
622 struct lysp_load_module_check_data *info = data;
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100623 const char *filename, *dot, *rev, *name;
Radek Krejci9ed7a192018-10-31 16:23:51 +0100624 size_t len;
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100625 struct lysp_revision *revs;
626
627 name = mod ? mod->mod->name : submod->name;
628 revs = mod ? mod->revs : submod->revs;
Radek Krejci9ed7a192018-10-31 16:23:51 +0100629
630 if (info->name) {
631 /* check name of the parsed model */
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100632 if (strcmp(info->name, name)) {
633 LOGERR(ctx, LY_EINVAL, "Unexpected module \"%s\" parsed instead of \"%s\").", name, info->name);
Radek Krejci9ed7a192018-10-31 16:23:51 +0100634 return LY_EINVAL;
635 }
636 }
637 if (info->revision) {
638 /* check revision of the parsed model */
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100639 if (!revs || strcmp(info->revision, revs[0].date)) {
640 LOGERR(ctx, LY_EINVAL, "Module \"%s\" parsed with the wrong revision (\"%s\" instead \"%s\").", name,
Radek Krejcib07b5c92019-04-08 10:56:37 +0200641 revs ? revs[0].date : "none", info->revision);
Radek Krejci9ed7a192018-10-31 16:23:51 +0100642 return LY_EINVAL;
643 }
644 }
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100645 if (submod) {
646 assert(info->submoduleof);
647
Radek Krejci9ed7a192018-10-31 16:23:51 +0100648 /* check that the submodule belongs-to our module */
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100649 if (strcmp(info->submoduleof, submod->belongsto)) {
Radek Krejci9ed7a192018-10-31 16:23:51 +0100650 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 +0100651 submod->name, info->submoduleof, submod->belongsto);
Radek Krejci9ed7a192018-10-31 16:23:51 +0100652 return LY_EVALID;
653 }
654 /* check circular dependency */
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100655 if (submod->parsing) {
656 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE, "A circular dependency (include) for module \"%s\".", submod->name);
Radek Krejci9ed7a192018-10-31 16:23:51 +0100657 return LY_EVALID;
658 }
659 }
660 if (info->path) {
661 /* check that name and revision match filename */
662 filename = strrchr(info->path, '/');
663 if (!filename) {
664 filename = info->path;
665 } else {
666 filename++;
667 }
668 /* name */
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100669 len = strlen(name);
Radek Krejci9ed7a192018-10-31 16:23:51 +0100670 rev = strchr(filename, '@');
671 dot = strrchr(info->path, '.');
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100672 if (strncmp(filename, name, len) ||
Radek Krejci9ed7a192018-10-31 16:23:51 +0100673 ((rev && rev != &filename[len]) || (!rev && dot != &filename[len]))) {
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100674 LOGWRN(ctx, "File name \"%s\" does not match module name \"%s\".", filename, name);
Radek Krejci9ed7a192018-10-31 16:23:51 +0100675 }
676 /* revision */
677 if (rev) {
678 len = dot - ++rev;
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100679 if (!revs || len != 10 || strncmp(revs[0].date, rev, len)) {
Radek Krejci9ed7a192018-10-31 16:23:51 +0100680 LOGWRN(ctx, "File name \"%s\" does not match module revision \"%s\".", filename,
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100681 revs ? revs[0].date : "none");
Radek Krejci9ed7a192018-10-31 16:23:51 +0100682 }
683 }
684 }
685 return LY_SUCCESS;
686}
687
688LY_ERR
Radek Krejcie7b95092019-05-15 11:03:07 +0200689lys_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 +0100690 void **result)
Radek Krejci9ed7a192018-10-31 16:23:51 +0100691{
692 int fd;
693 char *filepath = NULL;
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100694 const char **fp;
Radek Krejci9ed7a192018-10-31 16:23:51 +0100695 LYS_INFORMAT format;
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100696 void *mod = NULL;
Radek Krejci9ed7a192018-10-31 16:23:51 +0100697 LY_ERR ret = LY_SUCCESS;
698 struct lysp_load_module_check_data check_data = {0};
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100699 char rpath[PATH_MAX];
Radek Krejci9ed7a192018-10-31 16:23:51 +0100700
701 LY_CHECK_RET(lys_search_localfile(ly_ctx_get_searchdirs(ctx), !(ctx->flags & LY_CTX_DISABLE_SEARCHDIR_CWD), name, revision,
702 &filepath, &format));
703 LY_CHECK_ERR_RET(!filepath, LOGERR(ctx, LY_ENOTFOUND, "Data model \"%s%s%s\" not found in local searchdirs.",
704 name, revision ? "@" : "", revision ? revision : ""), LY_ENOTFOUND);
705
706
707 LOGVRB("Loading schema from \"%s\" file.", filepath);
708
709 /* open the file */
710 fd = open(filepath, O_RDONLY);
711 LY_CHECK_ERR_GOTO(fd < 0, LOGERR(ctx, LY_ESYS, "Unable to open data model file \"%s\" (%s).",
712 filepath, strerror(errno)); ret = LY_ESYS, cleanup);
713
714 check_data.name = name;
715 check_data.revision = revision;
716 check_data.path = filepath;
Radek Krejci3b1f9292018-11-08 10:58:35 +0100717 mod = lys_parse_fd_(ctx, fd, format, implement, main_ctx,
Radek Krejci9ed7a192018-10-31 16:23:51 +0100718 lysp_load_module_check, &check_data);
719 close(fd);
720 LY_CHECK_ERR_GOTO(!mod, ly_errcode(ctx), cleanup);
721
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100722 if (main_ctx) {
723 fp = &((struct lysp_submodule*)mod)->filepath;
724 } else {
725 fp = &((struct lys_module*)mod)->filepath;
726 }
727 if (!(*fp)) {
Radek Krejci9ed7a192018-10-31 16:23:51 +0100728 if (realpath(filepath, rpath) != NULL) {
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100729 (*fp) = lydict_insert(ctx, rpath, 0);
Radek Krejci9ed7a192018-10-31 16:23:51 +0100730 } else {
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100731 (*fp) = lydict_insert(ctx, filepath, 0);
Radek Krejci9ed7a192018-10-31 16:23:51 +0100732 }
733 }
734
735 *result = mod;
736
737 /* success */
738cleanup:
739 free(filepath);
740 return ret;
741}
742
Radek Krejcid33273d2018-10-25 14:55:52 +0200743LY_ERR
Radek Krejci6d6e4e42018-10-29 13:28:19 +0100744lysp_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 +0200745{
Radek Krejci9ed7a192018-10-31 16:23:51 +0100746 const char *module_data = NULL;
Radek Krejci086c7132018-10-26 15:29:04 +0200747 LYS_INFORMAT format = LYS_IN_UNKNOWN;
Radek Krejci9ed7a192018-10-31 16:23:51 +0100748 void (*module_data_free)(void *module_data, void *user_data) = NULL;
749 struct lysp_load_module_check_data check_data = {0};
Radek Krejci0af46292019-01-11 16:02:31 +0100750 struct lys_module *m;
Radek Krejci086c7132018-10-26 15:29:04 +0200751
Radek Krejci0af46292019-01-11 16:02:31 +0100752 assert(mod);
753
754 if (!*mod) {
755 /* try to get the module from the context */
756 if (revision) {
Radek Krejcied5acc52019-04-25 15:57:04 +0200757 /* get the specific revision */
Radek Krejci0af46292019-01-11 16:02:31 +0100758 *mod = (struct lys_module*)ly_ctx_get_module(ctx, name, revision);
Radek Krejcied5acc52019-04-25 15:57:04 +0200759 } else if (implement) {
760 /* prefer the implemented module instead of the latest one */
761 *mod = (struct lys_module*)ly_ctx_get_module_implemented(ctx, name);
762 if (!*mod) {
763 /* there is no implemented module in the context, try to get the latest revision module */
764 goto latest_in_the_context;
765 }
Radek Krejci0af46292019-01-11 16:02:31 +0100766 } else {
Radek Krejcied5acc52019-04-25 15:57:04 +0200767 /* get the requested module of the latest revision in the context */
768latest_in_the_context:
Radek Krejci0af46292019-01-11 16:02:31 +0100769 *mod = (struct lys_module*)ly_ctx_get_module_latest(ctx, name);
770 }
Radek Krejci086c7132018-10-26 15:29:04 +0200771 }
772
Radek Krejci6d6e4e42018-10-29 13:28:19 +0100773 if (!(*mod) || (require_parsed && !(*mod)->parsed)) {
774 (*mod) = NULL;
775
Radek Krejci086c7132018-10-26 15:29:04 +0200776 /* check collision with other implemented revision */
777 if (implement && ly_ctx_get_module_implemented(ctx, name)) {
778 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE,
779 "Module \"%s\" is already present in other implemented revision.", name);
780 return LY_EDENIED;
781 }
782
Radek Krejci9ed7a192018-10-31 16:23:51 +0100783 /* module not present in the context, get the input data and parse it */
Radek Krejci086c7132018-10-26 15:29:04 +0200784 if (!(ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
785search_clb:
786 if (ctx->imp_clb) {
787 if (ctx->imp_clb(name, revision, NULL, NULL, ctx->imp_clb_data,
Radek Krejci9ed7a192018-10-31 16:23:51 +0100788 &format, &module_data, &module_data_free) == LY_SUCCESS) {
789 check_data.name = name;
790 check_data.revision = revision;
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100791 *mod = lys_parse_mem_module(ctx, module_data, format, implement,
792 lysp_load_module_check, &check_data);
Radek Krejci9ed7a192018-10-31 16:23:51 +0100793 if (module_data_free) {
794 module_data_free((void*)module_data, ctx->imp_clb_data);
795 }
Radek Krejci096235c2019-01-11 11:12:19 +0100796 if (*mod && implement && lys_compile(*mod, 0)) {
797 ly_set_rm(&ctx->list, *mod, NULL);
798 lys_module_free(*mod, NULL);
799 *mod = NULL;
800 }
Radek Krejci086c7132018-10-26 15:29:04 +0200801 }
802 }
803 if (!(*mod) && !(ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
804 goto search_file;
805 }
806 } else {
807search_file:
808 if (!(ctx->flags & LY_CTX_DISABLE_SEARCHDIRS)) {
809 /* module was not received from the callback or there is no callback set */
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100810 lys_module_localfile(ctx, name, revision, implement, NULL, (void **)mod);
Radek Krejci086c7132018-10-26 15:29:04 +0200811 }
812 if (!(*mod) && (ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
813 goto search_clb;
814 }
815 }
Radek Krejci9ed7a192018-10-31 16:23:51 +0100816
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100817 if ((*mod) && !revision && ((*mod)->latest_revision == 1)) {
Radek Krejci9ed7a192018-10-31 16:23:51 +0100818 /* update the latest_revision flag - here we have selected the latest available schema,
819 * consider that even the callback provides correct latest revision */
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100820 (*mod)->latest_revision = 2;
Radek Krejci9ed7a192018-10-31 16:23:51 +0100821 }
Radek Krejci086c7132018-10-26 15:29:04 +0200822 } else {
823 /* we have module from the current context */
Radek Krejci0af46292019-01-11 16:02:31 +0100824 if (implement) {
825 m = ly_ctx_get_module_implemented(ctx, name);
826 if (m && m != *mod) {
827 /* check collision with other implemented revision */
828 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE,
829 "Module \"%s\" is already present in other implemented revision.", name);
830 *mod = NULL;
831 return LY_EDENIED;
832 }
Radek Krejci086c7132018-10-26 15:29:04 +0200833 }
834
835 /* circular check */
Radek Krejcif8f882a2018-10-31 14:51:15 +0100836 if ((*mod)->parsed && (*mod)->parsed->parsing) {
Radek Krejci086c7132018-10-26 15:29:04 +0200837 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE, "A circular dependency (import) for module \"%s\".", name);
838 *mod = NULL;
839 return LY_EVALID;
840 }
841 }
842 if (!(*mod)) {
Radek Krejci9ed7a192018-10-31 16:23:51 +0100843 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE, "%s \"%s\" module failed.", implement ? "Loading" : "Importing", name);
Radek Krejci086c7132018-10-26 15:29:04 +0200844 return LY_EVALID;
845 }
846
847 if (implement) {
848 /* mark the module implemented, check for collision was already done */
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100849 (*mod)->implemented = 1;
Radek Krejci086c7132018-10-26 15:29:04 +0200850 }
Radek Krejci086c7132018-10-26 15:29:04 +0200851
852 return LY_SUCCESS;
853}
854
855LY_ERR
Radek Krejcie7b95092019-05-15 11:03:07 +0200856lysp_load_submodule(struct lys_parser_ctx *ctx, struct lysp_module *mod, struct lysp_include *inc)
Radek Krejcid33273d2018-10-25 14:55:52 +0200857{
Radek Krejci3eb299d2019-04-08 15:07:44 +0200858 struct lysp_submodule *submod = NULL;
Radek Krejcid33273d2018-10-25 14:55:52 +0200859 const char *submodule_data = NULL;
860 LYS_INFORMAT format = LYS_IN_UNKNOWN;
861 void (*submodule_data_free)(void *module_data, void *user_data) = NULL;
Radek Krejci9ed7a192018-10-31 16:23:51 +0100862 struct lysp_load_module_check_data check_data = {0};
Radek Krejcid33273d2018-10-25 14:55:52 +0200863
Radek Krejcibbe09a92018-11-08 09:36:54 +0100864 /* submodule not present in the context, get the input data and parse it */
Radek Krejci3b1f9292018-11-08 10:58:35 +0100865 if (!(ctx->ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
Radek Krejcid33273d2018-10-25 14:55:52 +0200866search_clb:
Radek Krejci3b1f9292018-11-08 10:58:35 +0100867 if (ctx->ctx->imp_clb) {
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100868 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 +0100869 &format, &submodule_data, &submodule_data_free) == LY_SUCCESS) {
870 check_data.name = inc->name;
871 check_data.revision = inc->rev[0] ? inc->rev : NULL;
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100872 check_data.submoduleof = mod->mod->name;
873 submod = lys_parse_mem_submodule(ctx->ctx, submodule_data, format, ctx,
874 lysp_load_module_check, &check_data);
Radek Krejcibbe09a92018-11-08 09:36:54 +0100875 if (submodule_data_free) {
Radek Krejci3b1f9292018-11-08 10:58:35 +0100876 submodule_data_free((void*)submodule_data, ctx->ctx->imp_clb_data);
Radek Krejcid33273d2018-10-25 14:55:52 +0200877 }
878 }
Radek Krejcid33273d2018-10-25 14:55:52 +0200879 }
Radek Krejci3b1f9292018-11-08 10:58:35 +0100880 if (!submod && !(ctx->ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
Radek Krejcibbe09a92018-11-08 09:36:54 +0100881 goto search_file;
Radek Krejcid33273d2018-10-25 14:55:52 +0200882 }
Radek Krejci2d31ea72018-10-25 15:46:42 +0200883 } else {
Radek Krejcibbe09a92018-11-08 09:36:54 +0100884search_file:
Radek Krejci3b1f9292018-11-08 10:58:35 +0100885 if (!(ctx->ctx->flags & LY_CTX_DISABLE_SEARCHDIRS)) {
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100886 /* submodule was not received from the callback or there is no callback set */
887 lys_module_localfile(ctx->ctx, inc->name, inc->rev[0] ? inc->rev : NULL, 0, ctx, (void**)&submod);
Radek Krejcibbe09a92018-11-08 09:36:54 +0100888 }
Radek Krejci3b1f9292018-11-08 10:58:35 +0100889 if (!submod && (ctx->ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
Radek Krejcibbe09a92018-11-08 09:36:54 +0100890 goto search_clb;
891 }
892 }
893 if (submod) {
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100894 if (!inc->rev[0] && (submod->latest_revision == 1)) {
Radek Krejcibbe09a92018-11-08 09:36:54 +0100895 /* update the latest_revision flag - here we have selected the latest available schema,
896 * consider that even the callback provides correct latest revision */
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100897 submod->latest_revision = 2;
Radek Krejcibbe09a92018-11-08 09:36:54 +0100898 }
899
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100900 inc->submodule = submod;
Radek Krejcid33273d2018-10-25 14:55:52 +0200901 }
902 if (!inc->submodule) {
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100903 LOGVAL(ctx->ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE, "Including \"%s\" submodule into \"%s\" failed.",
904 inc->name, mod->mod->name);
Radek Krejcid33273d2018-10-25 14:55:52 +0200905 return LY_EVALID;
906 }
907
908 return LY_SUCCESS;
909}
910
Radek Krejci01342af2019-01-03 15:18:08 +0100911#define FIND_MODULE(TYPE, MOD) \
Radek Krejcice8c1592018-10-29 15:35:51 +0100912 TYPE *imp; \
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100913 if (!strncmp((MOD)->mod->prefix, prefix, len) && (MOD)->mod->prefix[len] == '\0') { \
Radek Krejcice8c1592018-10-29 15:35:51 +0100914 /* it is the prefix of the module itself */ \
Radek Krejci0af46292019-01-11 16:02:31 +0100915 m = ly_ctx_get_module((MOD)->mod->ctx, (MOD)->mod->name, (MOD)->mod->revision); \
Radek Krejcice8c1592018-10-29 15:35:51 +0100916 } \
917 /* search in imports */ \
Radek Krejcibbe09a92018-11-08 09:36:54 +0100918 if (!m) { \
919 LY_ARRAY_FOR((MOD)->imports, TYPE, imp) { \
Radek Krejci01342af2019-01-03 15:18:08 +0100920 if (!strncmp(imp->prefix, prefix, len) && imp->prefix[len] == '\0') { \
Radek Krejcibbe09a92018-11-08 09:36:54 +0100921 m = imp->module; \
922 break; \
923 } \
Radek Krejcice8c1592018-10-29 15:35:51 +0100924 } \
Radek Krejcibbe09a92018-11-08 09:36:54 +0100925 }
Radek Krejcice8c1592018-10-29 15:35:51 +0100926
Radek Krejcibbe09a92018-11-08 09:36:54 +0100927struct lysc_module *
Radek Krejcia3045382018-11-22 14:30:31 +0100928lysc_module_find_prefix(const struct lysc_module *mod, const char *prefix, size_t len)
Radek Krejci151a5b72018-10-19 14:21:44 +0200929{
Radek Krejcibbe09a92018-11-08 09:36:54 +0100930 const struct lys_module *m = NULL;
931
Radek Krejci01342af2019-01-03 15:18:08 +0100932 FIND_MODULE(struct lysc_import, mod);
Radek Krejcibbe09a92018-11-08 09:36:54 +0100933 return m ? m->compiled : NULL;
Radek Krejcice8c1592018-10-29 15:35:51 +0100934}
Radek Krejci151a5b72018-10-19 14:21:44 +0200935
Radek Krejcibbe09a92018-11-08 09:36:54 +0100936struct lysp_module *
Radek Krejcia3045382018-11-22 14:30:31 +0100937lysp_module_find_prefix(const struct lysp_module *mod, const char *prefix, size_t len)
Radek Krejcice8c1592018-10-29 15:35:51 +0100938{
Radek Krejcibbe09a92018-11-08 09:36:54 +0100939 const struct lys_module *m = NULL;
940
Radek Krejci01342af2019-01-03 15:18:08 +0100941 FIND_MODULE(struct lysp_import, mod);
Radek Krejcibbe09a92018-11-08 09:36:54 +0100942 return m ? m->parsed : NULL;
Radek Krejcice8c1592018-10-29 15:35:51 +0100943}
Radek Krejci151a5b72018-10-19 14:21:44 +0200944
Radek Krejcice8c1592018-10-29 15:35:51 +0100945struct lys_module *
Radek Krejcia3045382018-11-22 14:30:31 +0100946lys_module_find_prefix(const struct lys_module *mod, const char *prefix, size_t len)
Radek Krejcice8c1592018-10-29 15:35:51 +0100947{
Radek Krejcibbe09a92018-11-08 09:36:54 +0100948 const struct lys_module *m = NULL;
949
Radek Krejcice8c1592018-10-29 15:35:51 +0100950 if (mod->compiled) {
Radek Krejci01342af2019-01-03 15:18:08 +0100951 FIND_MODULE(struct lysc_import, mod->compiled);
Radek Krejcice8c1592018-10-29 15:35:51 +0100952 } else {
Radek Krejci01342af2019-01-03 15:18:08 +0100953 FIND_MODULE(struct lysp_import, mod->parsed);
Radek Krejcibbe09a92018-11-08 09:36:54 +0100954 }
955 return (struct lys_module*)m;
956}
957
Radek Krejcia3045382018-11-22 14:30:31 +0100958const char *
Radek Krejci693262f2019-04-29 15:23:20 +0200959lys_prefix_find_module(const struct lys_module *mod, const struct lys_module *import)
960{
961 unsigned int u;
962
963 if (import == mod) {
964 return mod->prefix;
965 }
966
967 if (mod->parsed) {
968 LY_ARRAY_FOR(mod->parsed->imports, u) {
969 if (mod->parsed->imports[u].module == import) {
970 return mod->parsed->imports[u].prefix;
971 }
972 }
973 } else {
974 /* we don't have original information about the import's prefix,
975 * so the prefix of the import module itself is returned instead */
976 return import->prefix;
977 }
978
979 return NULL;
980}
981
982const char *
Radek Krejcia3045382018-11-22 14:30:31 +0100983lys_nodetype2str(uint16_t nodetype)
984{
985 switch(nodetype) {
986 case LYS_CONTAINER:
987 return "container";
988 case LYS_CHOICE:
989 return "choice";
990 case LYS_LEAF:
991 return "leaf";
992 case LYS_LEAFLIST:
993 return "leaf-list";
994 case LYS_LIST:
995 return "list";
996 case LYS_ANYXML:
997 return "anyxml";
998 case LYS_ANYDATA:
999 return "anydata";
Radek Krejcif12a1f02019-02-11 16:42:08 +01001000 case LYS_CASE:
1001 return "case";
Radek Krejcif538ce52019-03-05 10:46:14 +01001002 case LYS_ACTION:
1003 return "RPC/action";
1004 case LYS_NOTIF:
1005 return "Notification";
Radek Krejcifc81ea82019-04-18 13:27:22 +02001006 case LYS_USES:
1007 return "uses";
Radek Krejcia3045382018-11-22 14:30:31 +01001008 default:
1009 return "unknown";
1010 }
1011}
1012
Radek Krejci693262f2019-04-29 15:23:20 +02001013const char *
1014lys_datatype2str(LY_DATA_TYPE basetype)
1015{
1016 switch(basetype) {
1017 case LY_TYPE_BINARY:
1018 return "binary";
1019 case LY_TYPE_UINT8:
1020 return "uint8";
1021 case LY_TYPE_UINT16:
1022 return "uint16";
1023 case LY_TYPE_UINT32:
1024 return "uint32";
1025 case LY_TYPE_UINT64:
1026 return "uint64";
1027 case LY_TYPE_STRING:
1028 return "string";
1029 case LY_TYPE_BITS:
1030 return "bits";
1031 case LY_TYPE_BOOL:
1032 return "boolean";
1033 case LY_TYPE_DEC64:
1034 return "decimal64";
1035 case LY_TYPE_EMPTY:
1036 return "empty";
1037 case LY_TYPE_ENUM:
1038 return "enumeration";
1039 case LY_TYPE_IDENT:
1040 return "identityref";
1041 case LY_TYPE_INST:
1042 return "instance-identifier";
1043 case LY_TYPE_LEAFREF:
1044 return "leafref";
1045 case LY_TYPE_UNION:
1046 return "union";
1047 case LY_TYPE_INT8:
1048 return "int8";
1049 case LY_TYPE_INT16:
1050 return "int16";
1051 case LY_TYPE_INT32:
1052 return "int32";
1053 case LY_TYPE_INT64:
1054 return "int64";
1055 default:
1056 return "unknown";
1057 }
1058}
1059
Radek Krejci056d0a82018-12-06 16:57:25 +01001060API const struct lysp_tpdf *
1061lysp_node_typedefs(const struct lysp_node *node)
1062{
Radek Krejci0fb28562018-12-13 15:17:37 +01001063 switch (node->nodetype) {
1064 case LYS_CONTAINER:
1065 return ((struct lysp_node_container*)node)->typedefs;
1066 case LYS_LIST:
1067 return ((struct lysp_node_list*)node)->typedefs;
1068 case LYS_GROUPING:
1069 return ((struct lysp_grp*)node)->typedefs;
1070 case LYS_ACTION:
1071 return ((struct lysp_action*)node)->typedefs;
1072 case LYS_INOUT:
1073 return ((struct lysp_action_inout*)node)->typedefs;
1074 case LYS_NOTIF:
1075 return ((struct lysp_notif*)node)->typedefs;
1076 default:
Radek Krejci056d0a82018-12-06 16:57:25 +01001077 return NULL;
1078 }
1079}
1080
Radek Krejci53ea6152018-12-13 15:21:15 +01001081API const struct lysp_grp *
1082lysp_node_groupings(const struct lysp_node *node)
1083{
1084 switch (node->nodetype) {
1085 case LYS_CONTAINER:
1086 return ((struct lysp_node_container*)node)->groupings;
1087 case LYS_LIST:
1088 return ((struct lysp_node_list*)node)->groupings;
1089 case LYS_GROUPING:
1090 return ((struct lysp_grp*)node)->groupings;
1091 case LYS_ACTION:
1092 return ((struct lysp_action*)node)->groupings;
1093 case LYS_INOUT:
1094 return ((struct lysp_action_inout*)node)->groupings;
1095 case LYS_NOTIF:
1096 return ((struct lysp_notif*)node)->groupings;
1097 default:
1098 return NULL;
1099 }
1100}
1101
Radek Krejcibbe09a92018-11-08 09:36:54 +01001102struct lysp_action **
Radek Krejci056d0a82018-12-06 16:57:25 +01001103lysp_node_actions_p(struct lysp_node *node)
Radek Krejcibbe09a92018-11-08 09:36:54 +01001104{
1105 assert(node);
1106 switch (node->nodetype) {
1107 case LYS_CONTAINER:
1108 return &((struct lysp_node_container*)node)->actions;
1109 case LYS_LIST:
1110 return &((struct lysp_node_list*)node)->actions;
1111 case LYS_GROUPING:
1112 return &((struct lysp_grp*)node)->actions;
1113 case LYS_AUGMENT:
1114 return &((struct lysp_augment*)node)->actions;
1115 default:
1116 return NULL;
1117 }
1118}
1119
Radek Krejci056d0a82018-12-06 16:57:25 +01001120API const struct lysp_action *
1121lysp_node_actions(const struct lysp_node *node)
1122{
1123 struct lysp_action **actions;
1124 actions = lysp_node_actions_p((struct lysp_node*)node);
1125 if (actions) {
1126 return *actions;
1127 } else {
1128 return NULL;
1129 }
1130}
1131
Radek Krejcibbe09a92018-11-08 09:36:54 +01001132struct lysp_notif **
Radek Krejci056d0a82018-12-06 16:57:25 +01001133lysp_node_notifs_p(struct lysp_node *node)
Radek Krejcibbe09a92018-11-08 09:36:54 +01001134{
1135 assert(node);
1136 switch (node->nodetype) {
1137 case LYS_CONTAINER:
1138 return &((struct lysp_node_container*)node)->notifs;
1139 case LYS_LIST:
1140 return &((struct lysp_node_list*)node)->notifs;
1141 case LYS_GROUPING:
1142 return &((struct lysp_grp*)node)->notifs;
1143 case LYS_AUGMENT:
1144 return &((struct lysp_augment*)node)->notifs;
1145 default:
1146 return NULL;
1147 }
1148}
1149
Radek Krejci056d0a82018-12-06 16:57:25 +01001150API const struct lysp_notif *
1151lysp_node_notifs(const struct lysp_node *node)
1152{
1153 struct lysp_notif **notifs;
1154 notifs = lysp_node_notifs_p((struct lysp_node*)node);
1155 if (notifs) {
1156 return *notifs;
1157 } else {
1158 return NULL;
1159 }
1160}
1161
Radek Krejcibbe09a92018-11-08 09:36:54 +01001162struct lysp_node **
Radek Krejci056d0a82018-12-06 16:57:25 +01001163lysp_node_children_p(struct lysp_node *node)
Radek Krejcibbe09a92018-11-08 09:36:54 +01001164{
1165 assert(node);
1166 switch (node->nodetype) {
1167 case LYS_CONTAINER:
1168 return &((struct lysp_node_container*)node)->child;
1169 case LYS_CHOICE:
1170 return &((struct lysp_node_choice*)node)->child;
1171 case LYS_LIST:
1172 return &((struct lysp_node_list*)node)->child;
1173 case LYS_CASE:
1174 return &((struct lysp_node_case*)node)->child;
1175 case LYS_GROUPING:
1176 return &((struct lysp_grp*)node)->data;
1177 case LYS_AUGMENT:
1178 return &((struct lysp_augment*)node)->child;
1179 case LYS_INOUT:
1180 return &((struct lysp_action_inout*)node)->data;
1181 case LYS_NOTIF:
1182 return &((struct lysp_notif*)node)->data;
1183 default:
1184 return NULL;
1185 }
1186}
1187
Radek Krejci056d0a82018-12-06 16:57:25 +01001188API const struct lysp_node *
1189lysp_node_children(const struct lysp_node *node)
1190{
1191 struct lysp_node **children;
Radek Krejcie7b95092019-05-15 11:03:07 +02001192
1193 if (!node) {
1194 return NULL;
1195 }
1196
Radek Krejci056d0a82018-12-06 16:57:25 +01001197 children = lysp_node_children_p((struct lysp_node*)node);
1198 if (children) {
1199 return *children;
1200 } else {
1201 return NULL;
1202 }
1203}
1204
1205struct lysc_action **
1206lysc_node_actions_p(struct lysc_node *node)
1207{
1208 assert(node);
1209 switch (node->nodetype) {
1210 case LYS_CONTAINER:
1211 return &((struct lysc_node_container*)node)->actions;
1212 case LYS_LIST:
1213 return &((struct lysc_node_list*)node)->actions;
1214 default:
1215 return NULL;
1216 }
1217}
1218
1219API const struct lysc_action *
1220lysc_node_actions(const struct lysc_node *node)
1221{
1222 struct lysc_action **actions;
1223 actions = lysc_node_actions_p((struct lysc_node*)node);
1224 if (actions) {
1225 return *actions;
1226 } else {
1227 return NULL;
1228 }
1229}
1230
1231struct lysc_notif **
1232lysc_node_notifs_p(struct lysc_node *node)
1233{
1234 assert(node);
1235 switch (node->nodetype) {
1236 case LYS_CONTAINER:
1237 return &((struct lysc_node_container*)node)->notifs;
1238 case LYS_LIST:
1239 return &((struct lysc_node_list*)node)->notifs;
1240 default:
1241 return NULL;
1242 }
1243}
1244
1245API const struct lysc_notif *
1246lysc_node_notifs(const struct lysc_node *node)
1247{
1248 struct lysc_notif **notifs;
1249 notifs = lysc_node_notifs_p((struct lysc_node*)node);
1250 if (notifs) {
1251 return *notifs;
1252 } else {
1253 return NULL;
1254 }
1255}
1256
Radek Krejcibbe09a92018-11-08 09:36:54 +01001257struct lysc_node **
Radek Krejci6eeb58f2019-02-22 16:29:37 +01001258lysc_node_children_p(const struct lysc_node *node, uint16_t flags)
Radek Krejcibbe09a92018-11-08 09:36:54 +01001259{
1260 assert(node);
1261 switch (node->nodetype) {
1262 case LYS_CONTAINER:
1263 return &((struct lysc_node_container*)node)->child;
1264 case LYS_CHOICE:
Radek Krejcia3045382018-11-22 14:30:31 +01001265 if (((struct lysc_node_choice*)node)->cases) {
Radek Krejci95710c92019-02-11 15:49:55 +01001266 return &((struct lysc_node_choice*)node)->cases->child;
Radek Krejcia3045382018-11-22 14:30:31 +01001267 } else {
1268 return NULL;
1269 }
Radek Krejci01342af2019-01-03 15:18:08 +01001270 case LYS_CASE:
1271 return &((struct lysc_node_case*)node)->child;
Radek Krejcibbe09a92018-11-08 09:36:54 +01001272 case LYS_LIST:
1273 return &((struct lysc_node_list*)node)->child;
Radek Krejci6eeb58f2019-02-22 16:29:37 +01001274 case LYS_ACTION:
1275 if (flags & LYS_CONFIG_R) {
1276 return &((struct lysc_action*)node)->output.data;
1277 } else {
1278 /* LYS_CONFIG_W, but also the default case */
1279 return &((struct lysc_action*)node)->input.data;
1280 }
Radek Krejcifc11bd72019-04-11 16:00:05 +02001281 case LYS_NOTIF:
1282 return &((struct lysc_notif*)node)->data;
Radek Krejcibbe09a92018-11-08 09:36:54 +01001283 default:
1284 return NULL;
1285 }
1286}
1287
Radek Krejci056d0a82018-12-06 16:57:25 +01001288API const struct lysc_node *
Radek Krejci6eeb58f2019-02-22 16:29:37 +01001289lysc_node_children(const struct lysc_node *node, uint16_t flags)
Radek Krejcia3045382018-11-22 14:30:31 +01001290{
Radek Krejci056d0a82018-12-06 16:57:25 +01001291 struct lysc_node **children;
Radek Krejcie7b95092019-05-15 11:03:07 +02001292
1293 if (!node) {
1294 return NULL;
1295 }
1296
Radek Krejci6eeb58f2019-02-22 16:29:37 +01001297 children = lysc_node_children_p((struct lysc_node*)node, flags);
Radek Krejci056d0a82018-12-06 16:57:25 +01001298 if (children) {
1299 return *children;
1300 } else {
Radek Krejcia3045382018-11-22 14:30:31 +01001301 return NULL;
1302 }
1303}
1304
Radek Krejci96a0bfd2018-11-22 15:25:06 +01001305struct lys_module *
1306lysp_find_module(struct ly_ctx *ctx, const struct lysp_module *mod)
1307{
1308 unsigned int u;
1309
1310 for (u = 0; u < ctx->list.count; ++u) {
1311 if (((struct lys_module*)ctx->list.objs[u])->parsed == mod) {
1312 return ((struct lys_module*)ctx->list.objs[u]);
1313 }
1314 }
1315 return NULL;
1316}
1317
Radek Krejcid3ca0632019-04-16 16:54:54 +02001318unsigned int
1319lysp_ext_instance_iter(struct lysp_ext_instance *ext, unsigned int index, LYEXT_SUBSTMT substmt)
1320{
1321 LY_CHECK_ARG_RET(NULL, ext, LY_EINVAL);
1322
1323 for (; index < LY_ARRAY_SIZE(ext); index++) {
1324 if (ext[index].insubstmt == substmt) {
1325 return index;
1326 }
1327 }
1328
1329 return LY_ARRAY_SIZE(ext);
1330}
1331
1332