blob: 9c934bbefc40803857bba75361d66a9f5f49e9fc [file] [log] [blame]
Pavol Vican021488a2016-01-25 23:56:12 +01001/**
2 * @file parser_yang.c
3 * @author Pavol Vican
4 * @brief YANG parser for libyang
5 *
6 * Copyright (c) 2015 CESNET, z.s.p.o.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
16 * distribution.
17 * 3. Neither the name of the Company nor the names of its contributors
18 * may be used to endorse or promote products derived from this
19 * software without specific prior written permission.
20 */
21
22#include "parser_yang.h"
23#include "parser_yang_bis.h"
Pavol Vican6eb14e82016-02-03 12:27:13 +010024#include "parser.h"
Pavol Vicanf37eeaa2016-02-09 20:54:06 +010025#include "xpath.h"
Pavol Vican021488a2016-01-25 23:56:12 +010026
Pavol Vican2a064652016-02-02 22:54:34 +010027static int
28yang_check_string(struct lys_module *module, const char **target, char *what, char *where, char *value, int line)
29{
Pavol Vicanbf805472016-01-26 14:24:56 +010030 if (*target) {
Pavol Vican2a064652016-02-02 22:54:34 +010031 LOGVAL(LYE_TOOMANY, line, what, where);
Pavol Vicanbf805472016-01-26 14:24:56 +010032 free(value);
33 return 1;
34 } else {
Pavol Vican2a064652016-02-02 22:54:34 +010035 *target = lydict_insert_zc(module->ctx, value);
Pavol Vicanbf805472016-01-26 14:24:56 +010036 return 0;
37 }
38}
39
Pavol Vican2a064652016-02-02 22:54:34 +010040int
41yang_read_common(struct lys_module *module, char *value, int type, int line)
42{
Pavol Vican6eb14e82016-02-03 12:27:13 +010043 int ret = 0;
Pavol Vican021488a2016-01-25 23:56:12 +010044
45 switch (type) {
Pavol Vican2a064652016-02-02 22:54:34 +010046 case MODULE_KEYWORD:
47 module->name = lydict_insert_zc(module->ctx, value);
48 break;
49 case NAMESPACE_KEYWORD:
50 ret = yang_check_string(module, &module->ns, "namespace", "module", value, line);
51 break;
Pavol Vican1ca072c2016-02-03 13:03:56 +010052 case ORGANIZATION_KEYWORD:
53 ret = yang_check_string(module, &module->org, "organization", "module", value, line);
54 break;
55 case CONTACT_KEYWORD:
56 ret = yang_check_string(module, &module->contact, "contact", "module", value, line);
57 break;
Pavol Vican2a064652016-02-02 22:54:34 +010058 }
59
Pavol Vican021488a2016-01-25 23:56:12 +010060 return ret;
Pavol Vicanbf805472016-01-26 14:24:56 +010061}
62
Pavol Vican2a064652016-02-02 22:54:34 +010063int
64yang_read_prefix(struct lys_module *module, void *save, char *value, int type, int line)
65{
Pavol Vican6eb14e82016-02-03 12:27:13 +010066 int ret = 0;
Pavol Vicanbf805472016-01-26 14:24:56 +010067
Pavol Vican6eb14e82016-02-03 12:27:13 +010068 if (lyp_check_identifier(value, LY_IDENT_PREFIX, line, module, NULL)) {
69 free(value);
70 return EXIT_FAILURE;
71 }
Pavol Vicanbf805472016-01-26 14:24:56 +010072 switch (type){
Pavol Vican2a064652016-02-02 22:54:34 +010073 case MODULE_KEYWORD:
74 ret = yang_check_string(module, &module->prefix, "prefix", "module", value, line);
75 break;
Pavol Vican6eb14e82016-02-03 12:27:13 +010076 case IMPORT_KEYWORD:
77 ((struct lys_import *)save)->prefix = lydict_insert_zc(module->ctx, value);
78 break;
Pavol Vican2a064652016-02-02 22:54:34 +010079 }
Pavol Vican6eb14e82016-02-03 12:27:13 +010080
Pavol Vicanbf805472016-01-26 14:24:56 +010081 return ret;
82}
Pavol Vican6eb14e82016-02-03 12:27:13 +010083
84void *
85yang_elem_of_array(void **ptr, uint8_t *act_size, int type, int sizeof_struct)
86{
87 void *retval;
88
89 if (!(*act_size % LY_ARRAY_SIZE) && !(*ptr = ly_realloc(*ptr, (*act_size + LY_ARRAY_SIZE) * sizeof_struct))) {
90 LOGMEM;
91 return NULL;
92 }
93 switch (type) {
94 case IMPORT_KEYWORD:
95 retval = &((struct lys_import *)(*ptr))[*act_size];
96 break;
Pavol Vicanbedff692016-02-03 14:29:17 +010097 case REVISION_KEYWORD:
98 retval = &((struct lys_revision *)(*ptr))[*act_size];
99 break;
Pavol Vican6eb14e82016-02-03 12:27:13 +0100100 }
101 (*act_size)++;
102 memset(retval,0,sizeof_struct);
103 return retval;
104}
105
106int
107yang_fill_import(struct lys_module *module, struct lys_import *imp, char *value, int line)
108{
109 int count, i;
110
111 /* check for circular import, store it if passed */
112 if (!module->ctx->models.parsing) {
113 count = 0;
114 } else {
115 for (count = 0; module->ctx->models.parsing[count]; ++count) {
116 if (value == module->ctx->models.parsing[count]) {
117 LOGERR(LY_EVALID, "Circular import dependency on the module \"%s\".", value);
118 goto error;
119 }
120 }
121 }
122 ++count;
123 module->ctx->models.parsing =
124 ly_realloc(module->ctx->models.parsing, (count + 1) * sizeof *module->ctx->models.parsing);
125 if (!module->ctx->models.parsing) {
126 LOGMEM;
127 goto error;
128 }
129 module->ctx->models.parsing[count - 1] = value;
130 module->ctx->models.parsing[count] = NULL;
131
132 /* try to load the module */
133 imp->module = (struct lys_module *)ly_ctx_get_module(module->ctx, value, imp->rev[0] ? imp->rev : NULL);
134 if (!imp->module) {
135 /* whether to use a user callback is decided in the function */
136 imp->module = (struct lys_module *)ly_ctx_load_module(module->ctx, value, imp->rev[0] ? imp->rev : NULL);
137 }
138
139 /* remove the new module name now that its parsing is finished (even if failed) */
140 if (module->ctx->models.parsing[count] || (module->ctx->models.parsing[count - 1] != value)) {
141 LOGINT;
142 }
143 --count;
144 if (count) {
145 module->ctx->models.parsing[count] = NULL;
146 } else {
147 free(module->ctx->models.parsing);
148 module->ctx->models.parsing = NULL;
149 }
150
151 /* check the result */
152 if (!imp->module) {
153 LOGERR(LY_EVALID, "Importing \"%s\" module into \"%s\" failed.", value, module->name);
154 goto error;
155 }
156
157 module->imp_size++;
158
159 /* check duplicities in imported modules */
160 for (i = 0; i < module->imp_size - 1; i++) {
161 if (!strcmp(module->imp[i].module->name, module->imp[module->imp_size - 1].module->name)) {
162 LOGVAL(LYE_SPEC, line, "Importing module \"%s\" repeatedly.", module->imp[i].module->name);
163 goto error;
164 }
165 }
166
167 free(value);
168 return EXIT_SUCCESS;
169
170 error:
171
172 free(value);
173 return EXIT_FAILURE;
174}
Pavol Vican1ca072c2016-02-03 13:03:56 +0100175
176int
177yang_read_description(struct lys_module *module, void *node, char *value, int type, int line)
178{
179 int ret;
180
181 if (!node) {
182 ret = yang_check_string(module, &module->dsc, "description", "module", value, line);
Pavol Vicanbedff692016-02-03 14:29:17 +0100183 } else {
184 switch (type) {
185 case REVISION_KEYWORD:
186 ret = yang_check_string(module, &((struct lys_revision *) node)->dsc, "description", "revision", value, line);
187 break;
Pavol Vicane1354e92016-02-09 14:02:09 +0100188 case FEATURE_KEYWORD:
189 ret = yang_check_string(module, &((struct lys_feature *) node)->dsc, "description", "feature", value, line);
190 break;
Pavol Vicanbbdef532016-02-09 14:52:12 +0100191 case IDENTITY_KEYWORD:
192 ret = yang_check_string(module, &((struct lys_ident *) node)->dsc, "description", "identity", value, line);
193 break;
Pavol Vicanf37eeaa2016-02-09 20:54:06 +0100194 case MUST_KEYWORD:
195 ret = yang_check_string(module, &((struct lys_restr *) node)->dsc, "description", "must", value, line);
196 break;
Pavol Vicanbedff692016-02-03 14:29:17 +0100197 }
Pavol Vican1ca072c2016-02-03 13:03:56 +0100198 }
199 return ret;
200}
201
202int
203yang_read_reference(struct lys_module *module, void *node, char *value, int type, int line)
204{
205 int ret;
206
207 if (!node) {
208 ret = yang_check_string(module, &module->ref, "reference", "module", value, line);
Pavol Vicanbedff692016-02-03 14:29:17 +0100209 } else {
210 switch (type) {
211 case REVISION_KEYWORD:
212 ret = yang_check_string(module, &((struct lys_revision *) node)->ref, "reference", "revision", value, line);
213 break;
Pavol Vicanbbdef532016-02-09 14:52:12 +0100214 case FEATURE_KEYWORD:
215 ret = yang_check_string(module, &((struct lys_feature *) node)->ref, "reference", "feature", value, line);
216 break;
217 case IDENTITY_KEYWORD:
218 ret = yang_check_string(module, &((struct lys_ident *) node)->ref, "reference", "identity", value, line);
219 break;
Pavol Vicanf37eeaa2016-02-09 20:54:06 +0100220 case MUST_KEYWORD:
221 ret = yang_check_string(module,&((struct lys_restr *) node)->ref, "reference", "must", value, line);
222 break;
Pavol Vicanbedff692016-02-03 14:29:17 +0100223 }
Pavol Vican1ca072c2016-02-03 13:03:56 +0100224 }
225 return ret;
226}
Pavol Vicanbedff692016-02-03 14:29:17 +0100227
228void *
229yang_read_revision(struct lys_module *module, char *value)
230{
231 struct lys_revision *retval;
232
Pavol Vican1eeb1992016-02-09 11:10:45 +0100233 retval = &module->rev[module->rev_size];
Pavol Vicanbedff692016-02-03 14:29:17 +0100234
235 /* first member of array is last revision */
Pavol Vican1eeb1992016-02-09 11:10:45 +0100236 if (module->rev_size && strcmp(module->rev[0].date, value) < 0) {
Pavol Vicanbedff692016-02-03 14:29:17 +0100237 memcpy(retval->date, module->rev[0].date, LY_REV_SIZE);
238 memcpy(module->rev[0].date, value, LY_REV_SIZE);
239 retval->dsc = module->rev[0].dsc;
240 retval->ref = module->rev[0].ref;
241 retval = module->rev;
242 retval->dsc = NULL;
243 retval->ref = NULL;
244 } else {
245 memcpy(retval->date, value, LY_REV_SIZE);
246 }
Pavol Vican1eeb1992016-02-09 11:10:45 +0100247 module->rev_size++;
Pavol Vicanbedff692016-02-03 14:29:17 +0100248 free(value);
249 return retval;
250}
Pavol Vican1eeb1992016-02-09 11:10:45 +0100251
252int
253yang_add_elem(struct lys_node_array **node, int *size)
254{
255 if (!*size % LY_ARRAY_SIZE) {
256 if (!(*node = ly_realloc(*node, (*size + LY_ARRAY_SIZE) * sizeof **node))) {
257 LOGMEM;
258 return EXIT_FAILURE;
259 } else {
260 memset(*node+*size,0,LY_ARRAY_SIZE*sizeof **node);
261 }
262 }
263 (*size)++;
264 return EXIT_SUCCESS;
265}
Pavol Vicane1354e92016-02-09 14:02:09 +0100266
267void *
268yang_read_feature(struct lys_module *module, char *value, int line)
269{
270 struct lys_feature *retval;
271
272 /* check uniqueness of feature's names */
273 if (lyp_check_identifier(value, LY_IDENT_FEATURE, line, module, NULL)) {
274 goto error;
275 }
276 retval = &module->features[module->features_size];
277 retval->name = lydict_insert_zc(module->ctx, value);
278 retval->module = module;
279 module->features_size++;
280 return retval;
281
282error:
283 free(value);
284 return NULL;
285}
286
287int
Pavol Vicanf37eeaa2016-02-09 20:54:06 +0100288yang_read_if_feature(struct lys_module *module, void *ptr, char *value, struct unres_schema *unres, int type, int line)
Pavol Vicane1354e92016-02-09 14:02:09 +0100289{
290 const char *exp;
291 int ret;
Pavol Vicanf37eeaa2016-02-09 20:54:06 +0100292 struct lys_feature *f;
293 struct lys_node *n;
Pavol Vicane1354e92016-02-09 14:02:09 +0100294
295 if (!(exp = transform_schema2json(module, value, line))) {
296 free(value);
297 return EXIT_FAILURE;
298 }
299 free(value);
300
301 /* hack - store pointer to the parent node for later status check */
Pavol Vicanf37eeaa2016-02-09 20:54:06 +0100302 if (type == FEATURE_KEYWORD) {
303 f = (struct lys_feature *) ptr;
304 f->features[f->features_size] = f;
305 ret = unres_schema_add_str(module, unres, &f->features[f->features_size], UNRES_IFFEAT, exp, line);
306 f->features_size++;
307 } else {
308 n = (struct lys_node *) ptr;
309 n->features[n->features_size] = (struct lys_feature *) n;
310 ret = unres_schema_add_str(module, unres, &n->features[n->features_size], UNRES_IFFEAT, exp, line);
311 n->features_size++;
312 }
Pavol Vicane1354e92016-02-09 14:02:09 +0100313
314 lydict_remove(module->ctx, exp);
315 if (ret == -1) {
316
317 return EXIT_FAILURE;
318 }
319 return EXIT_SUCCESS;
320}
321
322static int
323yang_check_flags(uint8_t *flags, uint8_t mask, char *what, char *where, int value, int line)
324{
325 if (*flags & mask) {
326 LOGVAL(LYE_TOOMANY, line, what, where);
327 return EXIT_FAILURE;
328 } else {
329 *flags = value;
330 return EXIT_SUCCESS;
331 }
332}
333
334int
335yang_read_status(void *node, int value, int type, int line)
336{
337 int retval;
338
339 switch (type) {
340 case FEATURE_KEYWORD:
341 retval = yang_check_flags(&((struct lys_feature *) node)->flags, LYS_STATUS_MASK, "status", "feature", value, line);
342 break;
Pavol Vicanbbdef532016-02-09 14:52:12 +0100343 case IDENTITY_KEYWORD:
344 retval = yang_check_flags(&((struct lys_ident *) node)->flags, LYS_STATUS_MASK, "status", "identity", value, line);
345 break;
Pavol Vicane1354e92016-02-09 14:02:09 +0100346 }
347 return retval;
348}
Pavol Vicanbbdef532016-02-09 14:52:12 +0100349
350void *
351yang_read_identity(struct lys_module *module, char *value)
352{
353 struct lys_ident *ret;
354
355 ret = &module->ident[module->ident_size];
356 ret->name = lydict_insert_zc(module->ctx, value);
357 ret->module = module;
358 module->ident_size++;
359 return ret;
360}
361
362int
363yang_read_base(struct lys_module *module, struct lys_ident *ident, char *value, struct unres_schema *unres, int line)
364{
365 const char *exp;
366
367 if (ident->base) {
368 LOGVAL(LYE_TOOMANY, line, "base", "identity");
369 return EXIT_FAILURE;
370 }
Pavol Vicanbbdef532016-02-09 14:52:12 +0100371 exp = transform_schema2json(module, value, line);
372 free(value);
373 if (!exp) {
374 return EXIT_FAILURE;
375 }
376 if (unres_schema_add_str(module, unres, ident, UNRES_IDENT, exp, line) == -1) {
377 lydict_remove(module->ctx, exp);
378 return EXIT_FAILURE;
379 }
380 lydict_remove(module->ctx, exp);
381 return EXIT_SUCCESS;
382}
Pavol Vicanf37eeaa2016-02-09 20:54:06 +0100383
384void *
385yang_read_cont(struct lys_module *module, struct lys_node *parent, char *value)
386{
387 struct lys_node_container *cont;
388
389 cont = calloc(1, sizeof *cont);
390 if (!cont) {
391 LOGMEM;
392 return NULL;
393 }
394 cont->module = module;
395 cont->name = lydict_insert_zc(module->ctx, value);
396 cont->nodetype = LYS_CONTAINER;
397 cont->prev = (struct lys_node *)cont;
398 if (lys_node_addchild(parent, module->type ? ((struct lys_submodule *)module)->belongsto: module, (struct lys_node *)cont)) {
399 lydict_remove(module->ctx, cont->name);
400 free(cont);
401 return NULL;
402 }
403 return cont;
404}
405
406void *
407yang_read_must(struct lys_module *module, struct lys_node *node, char *value, int type, int line)
408{
409 struct lys_restr *retval;
410
411 switch (type) {
412 case CONTAINER_KEYWORD:
413 retval = &((struct lys_node_container *)node)->must[((struct lys_node_container *)node)->must_size];
414 break;
415 }
416 retval->expr = transform_schema2json(module, value, line);
417 if (!retval->expr || lyxp_syntax_check(retval->expr, line)) {
418 goto error;
419 }
420 free(value);
421 return retval;
422
423error:
424 free(value);
425 return NULL;
426}
427
428int
429yang_read_message(struct lys_module *module,struct lys_restr *save,char *value, int type, int message, int line)
430{
431 int ret;
432 char *exp;
433
434 switch (type) {
435 case MUST_KEYWORD:
436 exp = "must";
437 break;
438 }
439 if (message==ERROR_APP_TAG_KEYWORD) {
440 ret = yang_check_string(module, &save->eapptag, "error_app_tag", exp, value, line);
441 } else {
442 ret = yang_check_string(module, &save->emsg, "error_app_tag", exp, value, line);
443 }
444 return ret;
445}
Pavol Vicanb5687112016-02-09 22:35:59 +0100446
447int
448yang_read_presence(struct lys_module *module, struct lys_node_container *cont, char *value, int line)
449{
450 if (cont->presence) {
451 LOGVAL(LYE_TOOMANY, line, "presence", "container");
452 free(value);
453 return EXIT_FAILURE;
454 } else {
455 cont->presence = lydict_insert_zc(module->ctx, value);
456 return EXIT_SUCCESS;
457 }
458}
459
460int
461yang_read_config(void *node, int value, int type, int line)
462{
463 int ret;
464
465 switch (type) {
466 case CONTAINER_KEYWORD:
467 ret = yang_check_flags(&((struct lys_node_container *)node)->flags, LYS_CONFIG_MASK, "config", "container", value, line);
468 break;
469 }
470 return ret;
471}