blob: 6fda323cc64b28b066c6f24ae2d3bd5fac177213 [file] [log] [blame]
Radek Krejci86d106e2018-10-18 09:53:19 +02001/**
2 * @file tree_schema_helpers.c
3 * @author Radek Krejci <rkrejci@cesnet.cz>
4 * @brief Parsing and validation helper functions
5 *
6 * Copyright (c) 2015 - 2018 CESNET, z.s.p.o.
7 *
8 * This source code is licensed under BSD 3-Clause License (the "License").
9 * You may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * https://opensource.org/licenses/BSD-3-Clause
13 */
Radek Krejci9ed7a192018-10-31 16:23:51 +010014#include "common.h"
Radek Krejci86d106e2018-10-18 09:53:19 +020015
16#include <ctype.h>
Radek Krejci9ed7a192018-10-31 16:23:51 +010017#include <dirent.h>
18#include <errno.h>
19#include <fcntl.h>
Radek Krejci86d106e2018-10-18 09:53:19 +020020#include <limits.h>
Radek Krejci9ed7a192018-10-31 16:23:51 +010021#include <stdlib.h>
22#include <sys/stat.h>
23#include <sys/types.h>
24#include <unistd.h>
Radek Krejci86d106e2018-10-18 09:53:19 +020025#include <time.h>
26
27#include "libyang.h"
Radek Krejci86d106e2018-10-18 09:53:19 +020028#include "tree_schema_internal.h"
29
Radek Krejcia3045382018-11-22 14:30:31 +010030/**
31 * @brief Parse an identifier.
32 *
33 * ;; An identifier MUST NOT start with (('X'|'x') ('M'|'m') ('L'|'l'))
34 * identifier = (ALPHA / "_")
35 * *(ALPHA / DIGIT / "_" / "-" / ".")
36 *
37 * @param[in,out] id Identifier to parse. When returned, it points to the first character which is not part of the identifier.
38 * @return LY_ERR value: LY_SUCCESS or LY_EINVAL in case of invalid starting character.
39 */
40static LY_ERR
41lys_parse_id(const char **id)
42{
43 assert(id && *id);
44
Radek Krejcia9026eb2018-12-12 16:04:47 +010045 if (!is_yangidentstartchar(**id)) {
Radek Krejcia3045382018-11-22 14:30:31 +010046 return LY_EINVAL;
47 }
48 ++(*id);
49
Radek Krejcia9026eb2018-12-12 16:04:47 +010050 while (is_yangidentchar(**id)) {
Radek Krejcia3045382018-11-22 14:30:31 +010051 ++(*id);
52 }
53 return LY_SUCCESS;
54}
55
56LY_ERR
57lys_parse_nodeid(const char **id, const char **prefix, size_t *prefix_len, const char **name, size_t *name_len)
58{
59 assert(id && *id);
60 assert(prefix && prefix_len);
61 assert(name && name_len);
62
63 *prefix = *id;
64 *prefix_len = 0;
65 *name = NULL;
66 *name_len = 0;
67
68 LY_CHECK_RET(lys_parse_id(id));
69 if (**id == ':') {
70 /* there is prefix */
71 *prefix_len = *id - *prefix;
72 ++(*id);
73 *name = *id;
74
75 LY_CHECK_RET(lys_parse_id(id));
76 *name_len = *id - *name;
77 } else {
78 /* there is no prefix, so what we have as prefix now is actually the name */
79 *name = *prefix;
80 *name_len = *id - *name;
81 *prefix = NULL;
82 }
83
84 return LY_SUCCESS;
85}
86
Radek Krejci86d106e2018-10-18 09:53:19 +020087LY_ERR
Radek Krejci95710c92019-02-11 15:49:55 +010088lys_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 +010089 const struct lys_module *context_module, int nodetype, int implement,
90 const struct lysc_node **target, uint16_t *result_flag)
Radek Krejci9bb94eb2018-12-04 16:48:35 +010091{
92 LY_ERR ret = LY_EVALID;
93 const char *name, *prefix, *id;
Radek Krejci9bb94eb2018-12-04 16:48:35 +010094 size_t name_len, prefix_len;
Radek Krejci7af64242019-02-18 13:07:53 +010095 const struct lys_module *mod;
Radek Krejci95710c92019-02-11 15:49:55 +010096 const char *nodeid_type;
Radek Krejci6eeb58f2019-02-22 16:29:37 +010097 int getnext_extra_flag = 0;
Radek Krejci05b774b2019-02-25 13:26:18 +010098 int current_nodetype = 0;
Radek Krejci9bb94eb2018-12-04 16:48:35 +010099
100 assert(nodeid);
Radek Krejci9bb94eb2018-12-04 16:48:35 +0100101 assert(target);
Radek Krejci6eeb58f2019-02-22 16:29:37 +0100102 assert(result_flag);
Radek Krejci9bb94eb2018-12-04 16:48:35 +0100103 *target = NULL;
Radek Krejci6eeb58f2019-02-22 16:29:37 +0100104 *result_flag = 0;
Radek Krejci9bb94eb2018-12-04 16:48:35 +0100105
106 id = nodeid;
Radek Krejci95710c92019-02-11 15:49:55 +0100107
108 if (context_node) {
109 /* descendant-schema-nodeid */
110 nodeid_type = "descendant";
Radek Krejci3641f562019-02-13 15:38:40 +0100111
112 if (*id == '/') {
113 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
114 "Invalid descendant-schema-nodeid value \"%.*s\" - absolute-schema-nodeid used.",
115 nodeid_len ? nodeid_len : strlen(nodeid), nodeid);
116 return LY_EVALID;
117 }
Radek Krejci95710c92019-02-11 15:49:55 +0100118 } else {
119 /* absolute-schema-nodeid */
120 nodeid_type = "absolute";
Radek Krejci95710c92019-02-11 15:49:55 +0100121
122 if (*id != '/') {
123 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
124 "Invalid absolute-schema-nodeid value \"%.*s\" - missing starting \"/\".",
Radek Krejci3641f562019-02-13 15:38:40 +0100125 nodeid_len ? nodeid_len : strlen(nodeid), nodeid);
Radek Krejci95710c92019-02-11 15:49:55 +0100126 return LY_EVALID;
127 }
128 ++id;
129 }
130
Radek Krejci9bb94eb2018-12-04 16:48:35 +0100131 while (*id && (ret = lys_parse_nodeid(&id, &prefix, &prefix_len, &name, &name_len)) == LY_SUCCESS) {
132 if (prefix) {
Radek Krejci95710c92019-02-11 15:49:55 +0100133 mod = lys_module_find_prefix(context_module, prefix, prefix_len);
Radek Krejci9bb94eb2018-12-04 16:48:35 +0100134 if (!mod) {
135 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
Radek Krejci95710c92019-02-11 15:49:55 +0100136 "Invalid %s-schema-nodeid value \"%.*s\" - prefix \"%.*s\" not defined in module \"%s\".",
137 nodeid_type, id - nodeid, nodeid, prefix_len, prefix, context_module->name);
Radek Krejci9bb94eb2018-12-04 16:48:35 +0100138 return LY_ENOTFOUND;
139 }
140 } else {
Radek Krejci95710c92019-02-11 15:49:55 +0100141 mod = context_module;
142 }
143 if (implement && !mod->implemented) {
144 /* make the module implemented */
145 ly_ctx_module_implement_internal(ctx->ctx, (struct lys_module*)mod, 2);
Radek Krejci9bb94eb2018-12-04 16:48:35 +0100146 }
Radek Krejci6eeb58f2019-02-22 16:29:37 +0100147 if (context_node && context_node->nodetype == LYS_ACTION) {
148 /* move through input/output manually */
149 if (!strncmp("input", name, name_len)) {
150 (*result_flag) |= LYSC_OPT_RPC_INPUT;
Radek Krejci05b774b2019-02-25 13:26:18 +0100151 } else if (!strncmp("output", name, name_len)) {
Radek Krejci6eeb58f2019-02-22 16:29:37 +0100152 (*result_flag) |= LYSC_OPT_RPC_OUTPUT;
153 getnext_extra_flag = LYS_GETNEXT_OUTPUT;
Radek Krejci05b774b2019-02-25 13:26:18 +0100154 } else {
155 goto getnext;
Radek Krejci6eeb58f2019-02-22 16:29:37 +0100156 }
Radek Krejci05b774b2019-02-25 13:26:18 +0100157 current_nodetype = LYS_INOUT;
Radek Krejci6eeb58f2019-02-22 16:29:37 +0100158 } else {
Radek Krejci05b774b2019-02-25 13:26:18 +0100159getnext:
Radek Krejci6eeb58f2019-02-22 16:29:37 +0100160 context_node = lys_child(context_node, mod, name, name_len, 0,
161 getnext_extra_flag | LYS_GETNEXT_NOSTATECHECK | LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE);
162 if (!context_node) {
163 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
164 "Invalid %s-schema-nodeid value \"%.*s\" - target node not found.", nodeid_type, id - nodeid, nodeid);
165 return LY_ENOTFOUND;
166 }
167 getnext_extra_flag = 0;
Radek Krejci05b774b2019-02-25 13:26:18 +0100168 current_nodetype = context_node->nodetype;
Radek Krejci6eeb58f2019-02-22 16:29:37 +0100169
Radek Krejci05b774b2019-02-25 13:26:18 +0100170 if (current_nodetype == LYS_NOTIF) {
Radek Krejci6eeb58f2019-02-22 16:29:37 +0100171 (*result_flag) |= LYSC_OPT_NOTIFICATION;
172 }
Radek Krejci9bb94eb2018-12-04 16:48:35 +0100173 }
Radek Krejci01342af2019-01-03 15:18:08 +0100174 if (!*id || (nodeid_len && ((size_t)(id - nodeid) >= nodeid_len))) {
Radek Krejci9bb94eb2018-12-04 16:48:35 +0100175 break;
176 }
Radek Krejci01342af2019-01-03 15:18:08 +0100177 if (*id != '/') {
Radek Krejci9bb94eb2018-12-04 16:48:35 +0100178 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
Radek Krejci95710c92019-02-11 15:49:55 +0100179 "Invalid %s-schema-nodeid value \"%.*s\" - missing \"/\" as node-identifier separator.",
180 nodeid_type, id - nodeid + 1, nodeid);
Radek Krejci9bb94eb2018-12-04 16:48:35 +0100181 return LY_EVALID;
182 }
183 ++id;
184 }
185
186 if (ret == LY_SUCCESS) {
Radek Krejci7af64242019-02-18 13:07:53 +0100187 *target = context_node;
Radek Krejci05b774b2019-02-25 13:26:18 +0100188 if (nodetype & LYS_INOUT) {
189 /* instead of input/output nodes, the RPC/action node is actually returned */
190 }
191 if (nodetype && !(current_nodetype & nodetype)) {
Radek Krejci9bb94eb2018-12-04 16:48:35 +0100192 return LY_EDENIED;
193 }
Radek Krejci95710c92019-02-11 15:49:55 +0100194 } else {
195 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
196 "Invalid %s-schema-nodeid value \"%.*s\" - unexpected end of expression.",
Radek Krejci3641f562019-02-13 15:38:40 +0100197 nodeid_type, nodeid_len ? nodeid_len : strlen(nodeid), nodeid);
Radek Krejci9bb94eb2018-12-04 16:48:35 +0100198 }
199
200 return ret;
201}
202
203LY_ERR
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100204lysp_check_prefix(struct ly_parser_ctx *ctx, struct lysp_import *imports, const char *module_prefix, const char **value)
Radek Krejci86d106e2018-10-18 09:53:19 +0200205{
206 struct lysp_import *i;
207
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100208 if (module_prefix && &module_prefix != value && !strcmp(module_prefix, *value)) {
Radek Krejci86d106e2018-10-18 09:53:19 +0200209 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_REFERENCE,
210 "Prefix \"%s\" already used as module prefix.", *value);
211 return LY_EEXIST;
212 }
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100213 LY_ARRAY_FOR(imports, struct lysp_import, i) {
214 if (i->prefix && &i->prefix != value && !strcmp(i->prefix, *value)) {
215 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_REFERENCE, "Prefix \"%s\" already used to import \"%s\" module.",
216 *value, i->name);
217 return LY_EEXIST;
Radek Krejci86d106e2018-10-18 09:53:19 +0200218 }
219 }
220 return LY_SUCCESS;
221}
222
223LY_ERR
Radek Krejci4f28eda2018-11-12 11:46:16 +0100224lysc_check_status(struct lysc_ctx *ctx,
225 uint16_t flags1, void *mod1, const char *name1,
226 uint16_t flags2, void *mod2, const char *name2)
227{
228 uint16_t flg1, flg2;
229
230 flg1 = (flags1 & LYS_STATUS_MASK) ? (flags1 & LYS_STATUS_MASK) : LYS_STATUS_CURR;
231 flg2 = (flags2 & LYS_STATUS_MASK) ? (flags2 & LYS_STATUS_MASK) : LYS_STATUS_CURR;
232
233 if ((flg1 < flg2) && (mod1 == mod2)) {
234 if (ctx) {
235 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
236 "A %s definition \"%s\" is not allowed to reference %s definition \"%s\".",
237 flg1 == LYS_STATUS_CURR ? "current" : "deprecated", name1,
238 flg2 == LYS_STATUS_OBSLT ? "obsolete" : "deprecated", name2);
239 }
240 return LY_EVALID;
241 }
242
243 return LY_SUCCESS;
244}
245
246LY_ERR
Radek Krejcibbe09a92018-11-08 09:36:54 +0100247lysp_check_date(struct ly_parser_ctx *ctx, const char *date, int date_len, const char *stmt)
Radek Krejci86d106e2018-10-18 09:53:19 +0200248{
249 int i;
250 struct tm tm, tm_;
251 char *r;
252
Radek Krejcibbe09a92018-11-08 09:36:54 +0100253 LY_CHECK_ARG_RET(ctx ? ctx->ctx : NULL, date, LY_EINVAL);
254 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 +0200255
256 /* check format */
257 for (i = 0; i < date_len; i++) {
258 if (i == 4 || i == 7) {
259 if (date[i] != '-') {
260 goto error;
261 }
262 } else if (!isdigit(date[i])) {
263 goto error;
264 }
265 }
266
267 /* check content, e.g. 2018-02-31 */
268 memset(&tm, 0, sizeof tm);
269 r = strptime(date, "%Y-%m-%d", &tm);
270 if (!r || r != &date[LY_REV_SIZE - 1]) {
271 goto error;
272 }
273 memcpy(&tm_, &tm, sizeof tm);
274 mktime(&tm_); /* mktime modifies tm_ if it refers invalid date */
275 if (tm.tm_mday != tm_.tm_mday) { /* e.g 2018-02-29 -> 2018-03-01 */
276 /* checking days is enough, since other errors
277 * have been checked by strptime() */
278 goto error;
279 }
280
281 return LY_SUCCESS;
282
283error:
Radek Krejcid33273d2018-10-25 14:55:52 +0200284 if (stmt) {
Radek Krejcibbe09a92018-11-08 09:36:54 +0100285 if (ctx) {
286 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LY_VCODE_INVAL, date_len, date, stmt);
287 } else {
288 LOGVAL(NULL, LY_VLOG_NONE, NULL, LY_VCODE_INVAL, date_len, date, stmt);
289 }
Radek Krejcid33273d2018-10-25 14:55:52 +0200290 }
Radek Krejci86d106e2018-10-18 09:53:19 +0200291 return LY_EINVAL;
292}
293
294void
295lysp_sort_revisions(struct lysp_revision *revs)
296{
297 uint8_t i, r;
298 struct lysp_revision rev;
299
300 for (i = 1, r = 0; revs && i < LY_ARRAY_SIZE(revs); i++) {
Radek Krejcib7db73a2018-10-24 14:18:40 +0200301 if (strcmp(revs[i].date, revs[r].date) > 0) {
Radek Krejci86d106e2018-10-18 09:53:19 +0200302 r = i;
303 }
304 }
305
306 if (r) {
307 /* the newest revision is not on position 0, switch them */
Radek Krejci2c4e7172018-10-19 15:56:26 +0200308 memcpy(&rev, &revs[0], sizeof rev);
309 memcpy(&revs[0], &revs[r], sizeof rev);
310 memcpy(&revs[r], &rev, sizeof rev);
Radek Krejci86d106e2018-10-18 09:53:19 +0200311 }
312}
Radek Krejci151a5b72018-10-19 14:21:44 +0200313
Radek Krejcibbe09a92018-11-08 09:36:54 +0100314static const struct lysp_tpdf *
315lysp_type_match(const char *name, struct lysp_node *node)
316{
Radek Krejci0fb28562018-12-13 15:17:37 +0100317 const struct lysp_tpdf *typedefs;
Radek Krejcibbe09a92018-11-08 09:36:54 +0100318 unsigned int u;
319
Radek Krejci0fb28562018-12-13 15:17:37 +0100320 typedefs = lysp_node_typedefs(node);
321 LY_ARRAY_FOR(typedefs, u) {
322 if (!strcmp(name, typedefs[u].name)) {
323 /* match */
324 return &typedefs[u];
Radek Krejcibbe09a92018-11-08 09:36:54 +0100325 }
326 }
327
328 return NULL;
329}
330
Radek Krejci4f28eda2018-11-12 11:46:16 +0100331static LY_DATA_TYPE
332lysp_type_str2builtin(const char *name, size_t len)
333{
334 if (len >= 4) { /* otherwise it does not match any built-in type */
335 if (name[0] == 'b') {
336 if (name[1] == 'i') {
337 if (len == 6 && !strncmp(&name[2], "nary", 4)) {
338 return LY_TYPE_BINARY;
339 } else if (len == 4 && !strncmp(&name[2], "ts", 2)) {
340 return LY_TYPE_BITS;
341 }
342 } else if (len == 7 && !strncmp(&name[1], "oolean", 6)) {
343 return LY_TYPE_BOOL;
344 }
345 } else if (name[0] == 'd') {
346 if (len == 9 && !strncmp(&name[1], "ecimal64", 8)) {
347 return LY_TYPE_DEC64;
348 }
349 } else if (name[0] == 'e') {
350 if (len == 5 && !strncmp(&name[1], "mpty", 4)) {
351 return LY_TYPE_EMPTY;
352 } else if (len == 11 && !strncmp(&name[1], "numeration", 10)) {
353 return LY_TYPE_ENUM;
354 }
355 } else if (name[0] == 'i') {
356 if (name[1] == 'n') {
357 if (len == 4 && !strncmp(&name[2], "t8", 2)) {
358 return LY_TYPE_INT8;
359 } else if (len == 5) {
360 if (!strncmp(&name[2], "t16", 3)) {
361 return LY_TYPE_INT16;
362 } else if (!strncmp(&name[2], "t32", 3)) {
363 return LY_TYPE_INT32;
364 } else if (!strncmp(&name[2], "t64", 3)) {
365 return LY_TYPE_INT64;
366 }
367 } else if (len == 19 && !strncmp(&name[2], "stance-identifier", 17)) {
368 return LY_TYPE_INST;
369 }
370 } else if (len == 11 && !strncmp(&name[1], "dentityref", 10)) {
371 return LY_TYPE_IDENT;
372 }
373 } else if (name[0] == 'l') {
374 if (len == 7 && !strncmp(&name[1], "eafref", 6)) {
375 return LY_TYPE_LEAFREF;
376 }
377 } else if (name[0] == 's') {
378 if (len == 6 && !strncmp(&name[1], "tring", 5)) {
379 return LY_TYPE_STRING;
380 }
381 } else if (name[0] == 'u') {
382 if (name[1] == 'n') {
383 if (len == 5 && !strncmp(&name[2], "ion", 3)) {
384 return LY_TYPE_UNION;
385 }
386 } else if (name[1] == 'i' && name[2] == 'n' && name[3] == 't') {
387 if (len == 5 && name[4] == '8') {
388 return LY_TYPE_UINT8;
389 } else if (len == 6) {
390 if (!strncmp(&name[4], "16", 2)) {
391 return LY_TYPE_UINT16;
392 } else if (!strncmp(&name[4], "32", 2)) {
393 return LY_TYPE_UINT32;
394 } else if (!strncmp(&name[4], "64", 2)) {
395 return LY_TYPE_UINT64;
396 }
397 }
398 }
399 }
400 }
401
402 return LY_TYPE_UNKNOWN;
403}
404
Radek Krejcibbe09a92018-11-08 09:36:54 +0100405LY_ERR
406lysp_type_find(const char *id, struct lysp_node *start_node, struct lysp_module *start_module,
Radek Krejci4f28eda2018-11-12 11:46:16 +0100407 LY_DATA_TYPE *type, const struct lysp_tpdf **tpdf, struct lysp_node **node, struct lysp_module **module)
Radek Krejcibbe09a92018-11-08 09:36:54 +0100408{
409 const char *str, *name;
410 struct lysp_tpdf *typedefs;
411 unsigned int u, v;
412
413 assert(id);
414 assert(start_module);
415 assert(tpdf);
416 assert(node);
417 assert(module);
418
Radek Krejci4f28eda2018-11-12 11:46:16 +0100419 *node = NULL;
Radek Krejcibbe09a92018-11-08 09:36:54 +0100420 str = strchr(id, ':');
421 if (str) {
422 *module = lysp_module_find_prefix(start_module, id, str - id);
423 name = str + 1;
Radek Krejci4f28eda2018-11-12 11:46:16 +0100424 *type = LY_TYPE_UNKNOWN;
Radek Krejcibbe09a92018-11-08 09:36:54 +0100425 } else {
426 *module = start_module;
427 name = id;
Radek Krejci4f28eda2018-11-12 11:46:16 +0100428
429 /* check for built-in types */
430 *type = lysp_type_str2builtin(name, strlen(name));
431 if (*type) {
432 *tpdf = NULL;
433 return LY_SUCCESS;
434 }
Radek Krejcibbe09a92018-11-08 09:36:54 +0100435 }
436 LY_CHECK_RET(!(*module), LY_ENOTFOUND);
437
438 if (start_node && *module == start_module) {
439 /* search typedefs in parent's nodes */
440 *node = start_node;
441 while (*node) {
442 *tpdf = lysp_type_match(name, *node);
443 if (*tpdf) {
444 /* match */
445 return LY_SUCCESS;
446 }
447 *node = (*node)->parent;
448 }
449 }
450
451 /* search in top-level typedefs */
452 if ((*module)->typedefs) {
453 LY_ARRAY_FOR((*module)->typedefs, u) {
454 if (!strcmp(name, (*module)->typedefs[u].name)) {
455 /* match */
456 *tpdf = &(*module)->typedefs[u];
457 return LY_SUCCESS;
458 }
459 }
460 }
461
462 /* search in submodules' typedefs */
463 LY_ARRAY_FOR((*module)->includes, u) {
464 typedefs = (*module)->includes[u].submodule->typedefs;
Radek Krejci76b3e962018-12-14 17:01:25 +0100465 LY_ARRAY_FOR(typedefs, v) {
466 if (!strcmp(name, typedefs[v].name)) {
467 /* match */
468 *tpdf = &typedefs[v];
469 return LY_SUCCESS;
Radek Krejcibbe09a92018-11-08 09:36:54 +0100470 }
471 }
472 }
473
474 return LY_ENOTFOUND;
475}
476
477/*
478 * @brief Check name of a new type to avoid name collisions.
479 *
480 * @param[in] ctx Parser context, module where the type is being defined is taken from here.
481 * @param[in] node Schema node where the type is being defined, NULL in case of a top-level typedef.
482 * @param[in] tpdf Typedef definition to check.
483 * @param[in,out] tpdfs_global Initialized hash table to store temporary data between calls. When the module's
484 * typedefs are checked, caller is supposed to free the table.
485 * @param[in,out] tpdfs_global Initialized hash table to store temporary data between calls. When the module's
486 * typedefs are checked, caller is supposed to free the table.
487 * @return LY_EEXIST in case of collision, LY_SUCCESS otherwise.
488 */
489static LY_ERR
Radek Krejci0fb28562018-12-13 15:17:37 +0100490lysp_check_typedef(struct ly_parser_ctx *ctx, struct lysp_node *node, const struct lysp_tpdf *tpdf,
Radek Krejcibbe09a92018-11-08 09:36:54 +0100491 struct hash_table *tpdfs_global, struct hash_table *tpdfs_scoped)
492{
493 struct lysp_node *parent;
494 uint32_t hash;
495 size_t name_len;
496 const char *name;
497 unsigned int u;
Radek Krejci0fb28562018-12-13 15:17:37 +0100498 const struct lysp_tpdf *typedefs;
Radek Krejcibbe09a92018-11-08 09:36:54 +0100499
500 assert(ctx);
501 assert(tpdf);
502
503 name = tpdf->name;
504 name_len = strlen(name);
505
Radek Krejci4f28eda2018-11-12 11:46:16 +0100506 if (lysp_type_str2builtin(name, name_len)) {
507 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_SYNTAX_YANG,
508 "Invalid name \"%s\" of typedef - name collision with a built-in type.", name);
509 return LY_EEXIST;
Radek Krejcibbe09a92018-11-08 09:36:54 +0100510 }
511
512 /* check locally scoped typedefs (avoid name shadowing) */
513 if (node) {
Radek Krejci0fb28562018-12-13 15:17:37 +0100514 typedefs = lysp_node_typedefs(node);
515 LY_ARRAY_FOR(typedefs, u) {
516 if (&typedefs[u] == tpdf) {
517 break;
518 }
519 if (!strcmp(name, typedefs[u].name)) {
520 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_SYNTAX_YANG,
521 "Invalid name \"%s\" of typedef - name collision with sibling type.", name);
522 return LY_EEXIST;
Radek Krejcibbe09a92018-11-08 09:36:54 +0100523 }
524 }
525 /* search typedefs in parent's nodes */
526 for (parent = node->parent; parent; parent = node->parent) {
527 if (lysp_type_match(name, parent)) {
528 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_SYNTAX_YANG,
529 "Invalid name \"%s\" of typedef - name collision with another scoped type.", name);
530 return LY_EEXIST;
531 }
532 }
533 }
534
535 /* check collision with the top-level typedefs */
536 hash = dict_hash(name, name_len);
537 if (node) {
538 lyht_insert(tpdfs_scoped, &name, hash, NULL);
539 if (!lyht_find(tpdfs_global, &name, hash, NULL)) {
540 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_SYNTAX_YANG,
541 "Invalid name \"%s\" of typedef - scoped type collide with a top-level type.", name);
542 return LY_EEXIST;
543 }
544 } else {
545 if (lyht_insert(tpdfs_global, &name, hash, NULL)) {
546 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_SYNTAX_YANG,
547 "Invalid name \"%s\" of typedef - name collision with another top-level type.", name);
548 return LY_EEXIST;
549 }
Radek Krejci3b1f9292018-11-08 10:58:35 +0100550 /* it is not necessary to test collision with the scoped types - in lysp_check_typedefs, all the
551 * top-level typedefs are inserted into the tables before the scoped typedefs, so the collision
552 * is detected in the first branch few lines above */
Radek Krejcibbe09a92018-11-08 09:36:54 +0100553 }
554
555 return LY_SUCCESS;
556}
557
558static int
559lysp_id_cmp(void *val1, void *val2, int UNUSED(mod), void *UNUSED(cb_data))
560{
561 return !strcmp(val1, val2);
562}
563
564LY_ERR
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100565lysp_check_typedefs(struct ly_parser_ctx *ctx, struct lysp_module *mod)
Radek Krejcibbe09a92018-11-08 09:36:54 +0100566{
567 struct hash_table *ids_global;
568 struct hash_table *ids_scoped;
Radek Krejci0fb28562018-12-13 15:17:37 +0100569 const struct lysp_tpdf *typedefs;
Radek Krejcibbe09a92018-11-08 09:36:54 +0100570 unsigned int i, u;
571 LY_ERR ret = LY_EVALID;
572
573 /* check name collisions - typedefs and groupings */
574 ids_global = lyht_new(8, sizeof(char*), lysp_id_cmp, NULL, 1);
575 ids_scoped = lyht_new(8, sizeof(char*), lysp_id_cmp, NULL, 1);
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100576 LY_ARRAY_FOR(mod->typedefs, i) {
577 if (lysp_check_typedef(ctx, NULL, &mod->typedefs[i], ids_global, ids_scoped)) {
Radek Krejcibbe09a92018-11-08 09:36:54 +0100578 goto cleanup;
579 }
580 }
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100581 LY_ARRAY_FOR(mod->includes, i) {
582 LY_ARRAY_FOR(mod->includes[i].submodule->typedefs, u) {
583 if (lysp_check_typedef(ctx, NULL, &mod->includes[i].submodule->typedefs[u], ids_global, ids_scoped)) {
Radek Krejci3b1f9292018-11-08 10:58:35 +0100584 goto cleanup;
585 }
586 }
587 }
Radek Krejcibbe09a92018-11-08 09:36:54 +0100588 for (u = 0; u < ctx->tpdfs_nodes.count; ++u) {
Radek Krejci0fb28562018-12-13 15:17:37 +0100589 typedefs = lysp_node_typedefs((struct lysp_node *)ctx->tpdfs_nodes.objs[u]);
590 LY_ARRAY_FOR(typedefs, i) {
591 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 +0100592 goto cleanup;
593 }
594 }
595 }
596 ret = LY_SUCCESS;
597cleanup:
598 lyht_free(ids_global);
599 lyht_free(ids_scoped);
600 ly_set_erase(&ctx->tpdfs_nodes, NULL);
601
602 return ret;
603}
604
Radek Krejci9ed7a192018-10-31 16:23:51 +0100605struct lysp_load_module_check_data {
606 const char *name;
607 const char *revision;
608 const char *path;
609 const char* submoduleof;
610};
611
612static LY_ERR
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100613lysp_load_module_check(struct ly_ctx *ctx, struct lysp_module *mod, struct lysp_submodule *submod, void *data)
Radek Krejci9ed7a192018-10-31 16:23:51 +0100614{
615 struct lysp_load_module_check_data *info = data;
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100616 const char *filename, *dot, *rev, *name;
Radek Krejci9ed7a192018-10-31 16:23:51 +0100617 size_t len;
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100618 struct lysp_revision *revs;
619
620 name = mod ? mod->mod->name : submod->name;
621 revs = mod ? mod->revs : submod->revs;
Radek Krejci9ed7a192018-10-31 16:23:51 +0100622
623 if (info->name) {
624 /* check name of the parsed model */
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100625 if (strcmp(info->name, name)) {
626 LOGERR(ctx, LY_EINVAL, "Unexpected module \"%s\" parsed instead of \"%s\").", name, info->name);
Radek Krejci9ed7a192018-10-31 16:23:51 +0100627 return LY_EINVAL;
628 }
629 }
630 if (info->revision) {
631 /* check revision of the parsed model */
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100632 if (!revs || strcmp(info->revision, revs[0].date)) {
633 LOGERR(ctx, LY_EINVAL, "Module \"%s\" parsed with the wrong revision (\"%s\" instead \"%s\").", name,
Radek Krejcib07b5c92019-04-08 10:56:37 +0200634 revs ? revs[0].date : "none", info->revision);
Radek Krejci9ed7a192018-10-31 16:23:51 +0100635 return LY_EINVAL;
636 }
637 }
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100638 if (submod) {
639 assert(info->submoduleof);
640
Radek Krejci9ed7a192018-10-31 16:23:51 +0100641 /* check that the submodule belongs-to our module */
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100642 if (strcmp(info->submoduleof, submod->belongsto)) {
Radek Krejci9ed7a192018-10-31 16:23:51 +0100643 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 +0100644 submod->name, info->submoduleof, submod->belongsto);
Radek Krejci9ed7a192018-10-31 16:23:51 +0100645 return LY_EVALID;
646 }
647 /* check circular dependency */
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100648 if (submod->parsing) {
649 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE, "A circular dependency (include) for module \"%s\".", submod->name);
Radek Krejci9ed7a192018-10-31 16:23:51 +0100650 return LY_EVALID;
651 }
652 }
653 if (info->path) {
654 /* check that name and revision match filename */
655 filename = strrchr(info->path, '/');
656 if (!filename) {
657 filename = info->path;
658 } else {
659 filename++;
660 }
661 /* name */
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100662 len = strlen(name);
Radek Krejci9ed7a192018-10-31 16:23:51 +0100663 rev = strchr(filename, '@');
664 dot = strrchr(info->path, '.');
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100665 if (strncmp(filename, name, len) ||
Radek Krejci9ed7a192018-10-31 16:23:51 +0100666 ((rev && rev != &filename[len]) || (!rev && dot != &filename[len]))) {
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100667 LOGWRN(ctx, "File name \"%s\" does not match module name \"%s\".", filename, name);
Radek Krejci9ed7a192018-10-31 16:23:51 +0100668 }
669 /* revision */
670 if (rev) {
671 len = dot - ++rev;
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100672 if (!revs || len != 10 || strncmp(revs[0].date, rev, len)) {
Radek Krejci9ed7a192018-10-31 16:23:51 +0100673 LOGWRN(ctx, "File name \"%s\" does not match module revision \"%s\".", filename,
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100674 revs ? revs[0].date : "none");
Radek Krejci9ed7a192018-10-31 16:23:51 +0100675 }
676 }
677 }
678 return LY_SUCCESS;
679}
680
681LY_ERR
Radek Krejci3b1f9292018-11-08 10:58:35 +0100682lys_module_localfile(struct ly_ctx *ctx, const char *name, const char *revision, int implement, struct ly_parser_ctx *main_ctx,
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100683 void **result)
Radek Krejci9ed7a192018-10-31 16:23:51 +0100684{
685 int fd;
686 char *filepath = NULL;
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100687 const char **fp;
Radek Krejci9ed7a192018-10-31 16:23:51 +0100688 LYS_INFORMAT format;
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100689 void *mod = NULL;
Radek Krejci9ed7a192018-10-31 16:23:51 +0100690 LY_ERR ret = LY_SUCCESS;
691 struct lysp_load_module_check_data check_data = {0};
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100692 char rpath[PATH_MAX];
Radek Krejci9ed7a192018-10-31 16:23:51 +0100693
694 LY_CHECK_RET(lys_search_localfile(ly_ctx_get_searchdirs(ctx), !(ctx->flags & LY_CTX_DISABLE_SEARCHDIR_CWD), name, revision,
695 &filepath, &format));
696 LY_CHECK_ERR_RET(!filepath, LOGERR(ctx, LY_ENOTFOUND, "Data model \"%s%s%s\" not found in local searchdirs.",
697 name, revision ? "@" : "", revision ? revision : ""), LY_ENOTFOUND);
698
699
700 LOGVRB("Loading schema from \"%s\" file.", filepath);
701
702 /* open the file */
703 fd = open(filepath, O_RDONLY);
704 LY_CHECK_ERR_GOTO(fd < 0, LOGERR(ctx, LY_ESYS, "Unable to open data model file \"%s\" (%s).",
705 filepath, strerror(errno)); ret = LY_ESYS, cleanup);
706
707 check_data.name = name;
708 check_data.revision = revision;
709 check_data.path = filepath;
Radek Krejci3b1f9292018-11-08 10:58:35 +0100710 mod = lys_parse_fd_(ctx, fd, format, implement, main_ctx,
Radek Krejci9ed7a192018-10-31 16:23:51 +0100711 lysp_load_module_check, &check_data);
712 close(fd);
713 LY_CHECK_ERR_GOTO(!mod, ly_errcode(ctx), cleanup);
714
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100715 if (main_ctx) {
716 fp = &((struct lysp_submodule*)mod)->filepath;
717 } else {
718 fp = &((struct lys_module*)mod)->filepath;
719 }
720 if (!(*fp)) {
Radek Krejci9ed7a192018-10-31 16:23:51 +0100721 if (realpath(filepath, rpath) != NULL) {
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100722 (*fp) = lydict_insert(ctx, rpath, 0);
Radek Krejci9ed7a192018-10-31 16:23:51 +0100723 } else {
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100724 (*fp) = lydict_insert(ctx, filepath, 0);
Radek Krejci9ed7a192018-10-31 16:23:51 +0100725 }
726 }
727
728 *result = mod;
729
730 /* success */
731cleanup:
732 free(filepath);
733 return ret;
734}
735
Radek Krejcid33273d2018-10-25 14:55:52 +0200736LY_ERR
Radek Krejci6d6e4e42018-10-29 13:28:19 +0100737lysp_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 +0200738{
Radek Krejci9ed7a192018-10-31 16:23:51 +0100739 const char *module_data = NULL;
Radek Krejci086c7132018-10-26 15:29:04 +0200740 LYS_INFORMAT format = LYS_IN_UNKNOWN;
Radek Krejci9ed7a192018-10-31 16:23:51 +0100741 void (*module_data_free)(void *module_data, void *user_data) = NULL;
742 struct lysp_load_module_check_data check_data = {0};
Radek Krejci0af46292019-01-11 16:02:31 +0100743 struct lys_module *m;
Radek Krejci086c7132018-10-26 15:29:04 +0200744
Radek Krejci0af46292019-01-11 16:02:31 +0100745 assert(mod);
746
747 if (!*mod) {
748 /* try to get the module from the context */
749 if (revision) {
750 *mod = (struct lys_module*)ly_ctx_get_module(ctx, name, revision);
751 } else {
752 *mod = (struct lys_module*)ly_ctx_get_module_latest(ctx, name);
753 }
Radek Krejci086c7132018-10-26 15:29:04 +0200754 }
755
Radek Krejci6d6e4e42018-10-29 13:28:19 +0100756 if (!(*mod) || (require_parsed && !(*mod)->parsed)) {
757 (*mod) = NULL;
758
Radek Krejci086c7132018-10-26 15:29:04 +0200759 /* check collision with other implemented revision */
760 if (implement && ly_ctx_get_module_implemented(ctx, name)) {
761 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE,
762 "Module \"%s\" is already present in other implemented revision.", name);
763 return LY_EDENIED;
764 }
765
Radek Krejci9ed7a192018-10-31 16:23:51 +0100766 /* module not present in the context, get the input data and parse it */
Radek Krejci086c7132018-10-26 15:29:04 +0200767 if (!(ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
768search_clb:
769 if (ctx->imp_clb) {
770 if (ctx->imp_clb(name, revision, NULL, NULL, ctx->imp_clb_data,
Radek Krejci9ed7a192018-10-31 16:23:51 +0100771 &format, &module_data, &module_data_free) == LY_SUCCESS) {
772 check_data.name = name;
773 check_data.revision = revision;
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100774 *mod = lys_parse_mem_module(ctx, module_data, format, implement,
775 lysp_load_module_check, &check_data);
Radek Krejci9ed7a192018-10-31 16:23:51 +0100776 if (module_data_free) {
777 module_data_free((void*)module_data, ctx->imp_clb_data);
778 }
Radek Krejci096235c2019-01-11 11:12:19 +0100779 if (*mod && implement && lys_compile(*mod, 0)) {
780 ly_set_rm(&ctx->list, *mod, NULL);
781 lys_module_free(*mod, NULL);
782 *mod = NULL;
783 }
Radek Krejci086c7132018-10-26 15:29:04 +0200784 }
785 }
786 if (!(*mod) && !(ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
787 goto search_file;
788 }
789 } else {
790search_file:
791 if (!(ctx->flags & LY_CTX_DISABLE_SEARCHDIRS)) {
792 /* module was not received from the callback or there is no callback set */
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100793 lys_module_localfile(ctx, name, revision, implement, NULL, (void **)mod);
Radek Krejci086c7132018-10-26 15:29:04 +0200794 }
795 if (!(*mod) && (ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
796 goto search_clb;
797 }
798 }
Radek Krejci9ed7a192018-10-31 16:23:51 +0100799
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100800 if ((*mod) && !revision && ((*mod)->latest_revision == 1)) {
Radek Krejci9ed7a192018-10-31 16:23:51 +0100801 /* update the latest_revision flag - here we have selected the latest available schema,
802 * consider that even the callback provides correct latest revision */
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100803 (*mod)->latest_revision = 2;
Radek Krejci9ed7a192018-10-31 16:23:51 +0100804 }
Radek Krejci086c7132018-10-26 15:29:04 +0200805 } else {
806 /* we have module from the current context */
Radek Krejci0af46292019-01-11 16:02:31 +0100807 if (implement) {
808 m = ly_ctx_get_module_implemented(ctx, name);
809 if (m && m != *mod) {
810 /* check collision with other implemented revision */
811 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE,
812 "Module \"%s\" is already present in other implemented revision.", name);
813 *mod = NULL;
814 return LY_EDENIED;
815 }
Radek Krejci086c7132018-10-26 15:29:04 +0200816 }
817
818 /* circular check */
Radek Krejcif8f882a2018-10-31 14:51:15 +0100819 if ((*mod)->parsed && (*mod)->parsed->parsing) {
Radek Krejci086c7132018-10-26 15:29:04 +0200820 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE, "A circular dependency (import) for module \"%s\".", name);
821 *mod = NULL;
822 return LY_EVALID;
823 }
824 }
825 if (!(*mod)) {
Radek Krejci9ed7a192018-10-31 16:23:51 +0100826 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE, "%s \"%s\" module failed.", implement ? "Loading" : "Importing", name);
Radek Krejci086c7132018-10-26 15:29:04 +0200827 return LY_EVALID;
828 }
829
830 if (implement) {
831 /* mark the module implemented, check for collision was already done */
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100832 (*mod)->implemented = 1;
Radek Krejci086c7132018-10-26 15:29:04 +0200833 }
Radek Krejci086c7132018-10-26 15:29:04 +0200834
835 return LY_SUCCESS;
836}
837
838LY_ERR
Radek Krejci3b1f9292018-11-08 10:58:35 +0100839lysp_load_submodule(struct ly_parser_ctx *ctx, struct lysp_module *mod, struct lysp_include *inc)
Radek Krejcid33273d2018-10-25 14:55:52 +0200840{
Radek Krejci3eb299d2019-04-08 15:07:44 +0200841 struct lysp_submodule *submod = NULL;
Radek Krejcid33273d2018-10-25 14:55:52 +0200842 const char *submodule_data = NULL;
843 LYS_INFORMAT format = LYS_IN_UNKNOWN;
844 void (*submodule_data_free)(void *module_data, void *user_data) = NULL;
Radek Krejci9ed7a192018-10-31 16:23:51 +0100845 struct lysp_load_module_check_data check_data = {0};
Radek Krejcid33273d2018-10-25 14:55:52 +0200846
Radek Krejcibbe09a92018-11-08 09:36:54 +0100847 /* submodule not present in the context, get the input data and parse it */
Radek Krejci3b1f9292018-11-08 10:58:35 +0100848 if (!(ctx->ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
Radek Krejcid33273d2018-10-25 14:55:52 +0200849search_clb:
Radek Krejci3b1f9292018-11-08 10:58:35 +0100850 if (ctx->ctx->imp_clb) {
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100851 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 +0100852 &format, &submodule_data, &submodule_data_free) == LY_SUCCESS) {
853 check_data.name = inc->name;
854 check_data.revision = inc->rev[0] ? inc->rev : NULL;
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100855 check_data.submoduleof = mod->mod->name;
856 submod = lys_parse_mem_submodule(ctx->ctx, submodule_data, format, ctx,
857 lysp_load_module_check, &check_data);
Radek Krejcibbe09a92018-11-08 09:36:54 +0100858 if (submodule_data_free) {
Radek Krejci3b1f9292018-11-08 10:58:35 +0100859 submodule_data_free((void*)submodule_data, ctx->ctx->imp_clb_data);
Radek Krejcid33273d2018-10-25 14:55:52 +0200860 }
861 }
Radek Krejcid33273d2018-10-25 14:55:52 +0200862 }
Radek Krejci3b1f9292018-11-08 10:58:35 +0100863 if (!submod && !(ctx->ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
Radek Krejcibbe09a92018-11-08 09:36:54 +0100864 goto search_file;
Radek Krejcid33273d2018-10-25 14:55:52 +0200865 }
Radek Krejci2d31ea72018-10-25 15:46:42 +0200866 } else {
Radek Krejcibbe09a92018-11-08 09:36:54 +0100867search_file:
Radek Krejci3b1f9292018-11-08 10:58:35 +0100868 if (!(ctx->ctx->flags & LY_CTX_DISABLE_SEARCHDIRS)) {
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100869 /* submodule was not received from the callback or there is no callback set */
870 lys_module_localfile(ctx->ctx, inc->name, inc->rev[0] ? inc->rev : NULL, 0, ctx, (void**)&submod);
Radek Krejcibbe09a92018-11-08 09:36:54 +0100871 }
Radek Krejci3b1f9292018-11-08 10:58:35 +0100872 if (!submod && (ctx->ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
Radek Krejcibbe09a92018-11-08 09:36:54 +0100873 goto search_clb;
874 }
875 }
876 if (submod) {
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100877 if (!inc->rev[0] && (submod->latest_revision == 1)) {
Radek Krejcibbe09a92018-11-08 09:36:54 +0100878 /* update the latest_revision flag - here we have selected the latest available schema,
879 * consider that even the callback provides correct latest revision */
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100880 submod->latest_revision = 2;
Radek Krejcibbe09a92018-11-08 09:36:54 +0100881 }
882
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100883 inc->submodule = submod;
Radek Krejcid33273d2018-10-25 14:55:52 +0200884 }
885 if (!inc->submodule) {
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100886 LOGVAL(ctx->ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE, "Including \"%s\" submodule into \"%s\" failed.",
887 inc->name, mod->mod->name);
Radek Krejcid33273d2018-10-25 14:55:52 +0200888 return LY_EVALID;
889 }
890
891 return LY_SUCCESS;
892}
893
Radek Krejci01342af2019-01-03 15:18:08 +0100894#define FIND_MODULE(TYPE, MOD) \
Radek Krejcice8c1592018-10-29 15:35:51 +0100895 TYPE *imp; \
Radek Krejci0bcdaed2019-01-10 10:21:34 +0100896 if (!strncmp((MOD)->mod->prefix, prefix, len) && (MOD)->mod->prefix[len] == '\0') { \
Radek Krejcice8c1592018-10-29 15:35:51 +0100897 /* it is the prefix of the module itself */ \
Radek Krejci0af46292019-01-11 16:02:31 +0100898 m = ly_ctx_get_module((MOD)->mod->ctx, (MOD)->mod->name, (MOD)->mod->revision); \
Radek Krejcice8c1592018-10-29 15:35:51 +0100899 } \
900 /* search in imports */ \
Radek Krejcibbe09a92018-11-08 09:36:54 +0100901 if (!m) { \
902 LY_ARRAY_FOR((MOD)->imports, TYPE, imp) { \
Radek Krejci01342af2019-01-03 15:18:08 +0100903 if (!strncmp(imp->prefix, prefix, len) && imp->prefix[len] == '\0') { \
Radek Krejcibbe09a92018-11-08 09:36:54 +0100904 m = imp->module; \
905 break; \
906 } \
Radek Krejcice8c1592018-10-29 15:35:51 +0100907 } \
Radek Krejcibbe09a92018-11-08 09:36:54 +0100908 }
Radek Krejcice8c1592018-10-29 15:35:51 +0100909
Radek Krejcibbe09a92018-11-08 09:36:54 +0100910struct lysc_module *
Radek Krejcia3045382018-11-22 14:30:31 +0100911lysc_module_find_prefix(const struct lysc_module *mod, const char *prefix, size_t len)
Radek Krejci151a5b72018-10-19 14:21:44 +0200912{
Radek Krejcibbe09a92018-11-08 09:36:54 +0100913 const struct lys_module *m = NULL;
914
Radek Krejci01342af2019-01-03 15:18:08 +0100915 FIND_MODULE(struct lysc_import, mod);
Radek Krejcibbe09a92018-11-08 09:36:54 +0100916 return m ? m->compiled : NULL;
Radek Krejcice8c1592018-10-29 15:35:51 +0100917}
Radek Krejci151a5b72018-10-19 14:21:44 +0200918
Radek Krejcibbe09a92018-11-08 09:36:54 +0100919struct lysp_module *
Radek Krejcia3045382018-11-22 14:30:31 +0100920lysp_module_find_prefix(const struct lysp_module *mod, const char *prefix, size_t len)
Radek Krejcice8c1592018-10-29 15:35:51 +0100921{
Radek Krejcibbe09a92018-11-08 09:36:54 +0100922 const struct lys_module *m = NULL;
923
Radek Krejci01342af2019-01-03 15:18:08 +0100924 FIND_MODULE(struct lysp_import, mod);
Radek Krejcibbe09a92018-11-08 09:36:54 +0100925 return m ? m->parsed : NULL;
Radek Krejcice8c1592018-10-29 15:35:51 +0100926}
Radek Krejci151a5b72018-10-19 14:21:44 +0200927
Radek Krejcice8c1592018-10-29 15:35:51 +0100928struct lys_module *
Radek Krejcia3045382018-11-22 14:30:31 +0100929lys_module_find_prefix(const struct lys_module *mod, const char *prefix, size_t len)
Radek Krejcice8c1592018-10-29 15:35:51 +0100930{
Radek Krejcibbe09a92018-11-08 09:36:54 +0100931 const struct lys_module *m = NULL;
932
Radek Krejcice8c1592018-10-29 15:35:51 +0100933 if (mod->compiled) {
Radek Krejci01342af2019-01-03 15:18:08 +0100934 FIND_MODULE(struct lysc_import, mod->compiled);
Radek Krejcice8c1592018-10-29 15:35:51 +0100935 } else {
Radek Krejci01342af2019-01-03 15:18:08 +0100936 FIND_MODULE(struct lysp_import, mod->parsed);
Radek Krejcibbe09a92018-11-08 09:36:54 +0100937 }
938 return (struct lys_module*)m;
939}
940
Radek Krejcia3045382018-11-22 14:30:31 +0100941const char *
942lys_nodetype2str(uint16_t nodetype)
943{
944 switch(nodetype) {
945 case LYS_CONTAINER:
946 return "container";
947 case LYS_CHOICE:
948 return "choice";
949 case LYS_LEAF:
950 return "leaf";
951 case LYS_LEAFLIST:
952 return "leaf-list";
953 case LYS_LIST:
954 return "list";
955 case LYS_ANYXML:
956 return "anyxml";
957 case LYS_ANYDATA:
958 return "anydata";
Radek Krejcif12a1f02019-02-11 16:42:08 +0100959 case LYS_CASE:
960 return "case";
Radek Krejcif538ce52019-03-05 10:46:14 +0100961 case LYS_ACTION:
962 return "RPC/action";
963 case LYS_NOTIF:
964 return "Notification";
Radek Krejcia3045382018-11-22 14:30:31 +0100965 default:
966 return "unknown";
967 }
968}
969
Radek Krejci056d0a82018-12-06 16:57:25 +0100970API const struct lysp_tpdf *
971lysp_node_typedefs(const struct lysp_node *node)
972{
Radek Krejci0fb28562018-12-13 15:17:37 +0100973 switch (node->nodetype) {
974 case LYS_CONTAINER:
975 return ((struct lysp_node_container*)node)->typedefs;
976 case LYS_LIST:
977 return ((struct lysp_node_list*)node)->typedefs;
978 case LYS_GROUPING:
979 return ((struct lysp_grp*)node)->typedefs;
980 case LYS_ACTION:
981 return ((struct lysp_action*)node)->typedefs;
982 case LYS_INOUT:
983 return ((struct lysp_action_inout*)node)->typedefs;
984 case LYS_NOTIF:
985 return ((struct lysp_notif*)node)->typedefs;
986 default:
Radek Krejci056d0a82018-12-06 16:57:25 +0100987 return NULL;
988 }
989}
990
Radek Krejci53ea6152018-12-13 15:21:15 +0100991API const struct lysp_grp *
992lysp_node_groupings(const struct lysp_node *node)
993{
994 switch (node->nodetype) {
995 case LYS_CONTAINER:
996 return ((struct lysp_node_container*)node)->groupings;
997 case LYS_LIST:
998 return ((struct lysp_node_list*)node)->groupings;
999 case LYS_GROUPING:
1000 return ((struct lysp_grp*)node)->groupings;
1001 case LYS_ACTION:
1002 return ((struct lysp_action*)node)->groupings;
1003 case LYS_INOUT:
1004 return ((struct lysp_action_inout*)node)->groupings;
1005 case LYS_NOTIF:
1006 return ((struct lysp_notif*)node)->groupings;
1007 default:
1008 return NULL;
1009 }
1010}
1011
Radek Krejcibbe09a92018-11-08 09:36:54 +01001012struct lysp_action **
Radek Krejci056d0a82018-12-06 16:57:25 +01001013lysp_node_actions_p(struct lysp_node *node)
Radek Krejcibbe09a92018-11-08 09:36:54 +01001014{
1015 assert(node);
1016 switch (node->nodetype) {
1017 case LYS_CONTAINER:
1018 return &((struct lysp_node_container*)node)->actions;
1019 case LYS_LIST:
1020 return &((struct lysp_node_list*)node)->actions;
1021 case LYS_GROUPING:
1022 return &((struct lysp_grp*)node)->actions;
1023 case LYS_AUGMENT:
1024 return &((struct lysp_augment*)node)->actions;
1025 default:
1026 return NULL;
1027 }
1028}
1029
Radek Krejci056d0a82018-12-06 16:57:25 +01001030API const struct lysp_action *
1031lysp_node_actions(const struct lysp_node *node)
1032{
1033 struct lysp_action **actions;
1034 actions = lysp_node_actions_p((struct lysp_node*)node);
1035 if (actions) {
1036 return *actions;
1037 } else {
1038 return NULL;
1039 }
1040}
1041
Radek Krejcibbe09a92018-11-08 09:36:54 +01001042struct lysp_notif **
Radek Krejci056d0a82018-12-06 16:57:25 +01001043lysp_node_notifs_p(struct lysp_node *node)
Radek Krejcibbe09a92018-11-08 09:36:54 +01001044{
1045 assert(node);
1046 switch (node->nodetype) {
1047 case LYS_CONTAINER:
1048 return &((struct lysp_node_container*)node)->notifs;
1049 case LYS_LIST:
1050 return &((struct lysp_node_list*)node)->notifs;
1051 case LYS_GROUPING:
1052 return &((struct lysp_grp*)node)->notifs;
1053 case LYS_AUGMENT:
1054 return &((struct lysp_augment*)node)->notifs;
1055 default:
1056 return NULL;
1057 }
1058}
1059
Radek Krejci056d0a82018-12-06 16:57:25 +01001060API const struct lysp_notif *
1061lysp_node_notifs(const struct lysp_node *node)
1062{
1063 struct lysp_notif **notifs;
1064 notifs = lysp_node_notifs_p((struct lysp_node*)node);
1065 if (notifs) {
1066 return *notifs;
1067 } else {
1068 return NULL;
1069 }
1070}
1071
Radek Krejcibbe09a92018-11-08 09:36:54 +01001072struct lysp_node **
Radek Krejci056d0a82018-12-06 16:57:25 +01001073lysp_node_children_p(struct lysp_node *node)
Radek Krejcibbe09a92018-11-08 09:36:54 +01001074{
1075 assert(node);
1076 switch (node->nodetype) {
1077 case LYS_CONTAINER:
1078 return &((struct lysp_node_container*)node)->child;
1079 case LYS_CHOICE:
1080 return &((struct lysp_node_choice*)node)->child;
1081 case LYS_LIST:
1082 return &((struct lysp_node_list*)node)->child;
1083 case LYS_CASE:
1084 return &((struct lysp_node_case*)node)->child;
1085 case LYS_GROUPING:
1086 return &((struct lysp_grp*)node)->data;
1087 case LYS_AUGMENT:
1088 return &((struct lysp_augment*)node)->child;
1089 case LYS_INOUT:
1090 return &((struct lysp_action_inout*)node)->data;
1091 case LYS_NOTIF:
1092 return &((struct lysp_notif*)node)->data;
1093 default:
1094 return NULL;
1095 }
1096}
1097
Radek Krejci056d0a82018-12-06 16:57:25 +01001098API const struct lysp_node *
1099lysp_node_children(const struct lysp_node *node)
1100{
1101 struct lysp_node **children;
1102 children = lysp_node_children_p((struct lysp_node*)node);
1103 if (children) {
1104 return *children;
1105 } else {
1106 return NULL;
1107 }
1108}
1109
1110struct lysc_action **
1111lysc_node_actions_p(struct lysc_node *node)
1112{
1113 assert(node);
1114 switch (node->nodetype) {
1115 case LYS_CONTAINER:
1116 return &((struct lysc_node_container*)node)->actions;
1117 case LYS_LIST:
1118 return &((struct lysc_node_list*)node)->actions;
1119 default:
1120 return NULL;
1121 }
1122}
1123
1124API const struct lysc_action *
1125lysc_node_actions(const struct lysc_node *node)
1126{
1127 struct lysc_action **actions;
1128 actions = lysc_node_actions_p((struct lysc_node*)node);
1129 if (actions) {
1130 return *actions;
1131 } else {
1132 return NULL;
1133 }
1134}
1135
1136struct lysc_notif **
1137lysc_node_notifs_p(struct lysc_node *node)
1138{
1139 assert(node);
1140 switch (node->nodetype) {
1141 case LYS_CONTAINER:
1142 return &((struct lysc_node_container*)node)->notifs;
1143 case LYS_LIST:
1144 return &((struct lysc_node_list*)node)->notifs;
1145 default:
1146 return NULL;
1147 }
1148}
1149
1150API const struct lysc_notif *
1151lysc_node_notifs(const struct lysc_node *node)
1152{
1153 struct lysc_notif **notifs;
1154 notifs = lysc_node_notifs_p((struct lysc_node*)node);
1155 if (notifs) {
1156 return *notifs;
1157 } else {
1158 return NULL;
1159 }
1160}
1161
Radek Krejcibbe09a92018-11-08 09:36:54 +01001162struct lysc_node **
Radek Krejci6eeb58f2019-02-22 16:29:37 +01001163lysc_node_children_p(const struct lysc_node *node, uint16_t flags)
Radek Krejcibbe09a92018-11-08 09:36:54 +01001164{
1165 assert(node);
1166 switch (node->nodetype) {
1167 case LYS_CONTAINER:
1168 return &((struct lysc_node_container*)node)->child;
1169 case LYS_CHOICE:
Radek Krejcia3045382018-11-22 14:30:31 +01001170 if (((struct lysc_node_choice*)node)->cases) {
Radek Krejci95710c92019-02-11 15:49:55 +01001171 return &((struct lysc_node_choice*)node)->cases->child;
Radek Krejcia3045382018-11-22 14:30:31 +01001172 } else {
1173 return NULL;
1174 }
Radek Krejci01342af2019-01-03 15:18:08 +01001175 case LYS_CASE:
1176 return &((struct lysc_node_case*)node)->child;
Radek Krejcibbe09a92018-11-08 09:36:54 +01001177 case LYS_LIST:
1178 return &((struct lysc_node_list*)node)->child;
Radek Krejci6eeb58f2019-02-22 16:29:37 +01001179 case LYS_ACTION:
1180 if (flags & LYS_CONFIG_R) {
1181 return &((struct lysc_action*)node)->output.data;
1182 } else {
1183 /* LYS_CONFIG_W, but also the default case */
1184 return &((struct lysc_action*)node)->input.data;
1185 }
Radek Krejcifc11bd72019-04-11 16:00:05 +02001186 case LYS_NOTIF:
1187 return &((struct lysc_notif*)node)->data;
Radek Krejcibbe09a92018-11-08 09:36:54 +01001188 default:
1189 return NULL;
1190 }
1191}
1192
Radek Krejci056d0a82018-12-06 16:57:25 +01001193API const struct lysc_node *
Radek Krejci6eeb58f2019-02-22 16:29:37 +01001194lysc_node_children(const struct lysc_node *node, uint16_t flags)
Radek Krejcia3045382018-11-22 14:30:31 +01001195{
Radek Krejci056d0a82018-12-06 16:57:25 +01001196 struct lysc_node **children;
Radek Krejci6eeb58f2019-02-22 16:29:37 +01001197 children = lysc_node_children_p((struct lysc_node*)node, flags);
Radek Krejci056d0a82018-12-06 16:57:25 +01001198 if (children) {
1199 return *children;
1200 } else {
Radek Krejcia3045382018-11-22 14:30:31 +01001201 return NULL;
1202 }
1203}
1204
Radek Krejci96a0bfd2018-11-22 15:25:06 +01001205struct lys_module *
1206lysp_find_module(struct ly_ctx *ctx, const struct lysp_module *mod)
1207{
1208 unsigned int u;
1209
1210 for (u = 0; u < ctx->list.count; ++u) {
1211 if (((struct lys_module*)ctx->list.objs[u])->parsed == mod) {
1212 return ((struct lys_module*)ctx->list.objs[u]);
1213 }
1214 }
1215 return NULL;
1216}
1217
Radek Krejcid3ca0632019-04-16 16:54:54 +02001218unsigned int
1219lysp_ext_instance_iter(struct lysp_ext_instance *ext, unsigned int index, LYEXT_SUBSTMT substmt)
1220{
1221 LY_CHECK_ARG_RET(NULL, ext, LY_EINVAL);
1222
1223 for (; index < LY_ARRAY_SIZE(ext); index++) {
1224 if (ext[index].insubstmt == substmt) {
1225 return index;
1226 }
1227 }
1228
1229 return LY_ARRAY_SIZE(ext);
1230}
1231
1232