blob: a9c99a9a7791741c9d8786bb9e0ac30fde439e87 [file] [log] [blame]
Radek Krejcif0e1ba52020-05-22 15:14:35 +02001/**
Michal Vaskoafac7822020-10-20 14:22:26 +02002 * @file in.c
Radek Krejcif0e1ba52020-05-22 15:14:35 +02003 * @author Radek Krejci <rkrejci@cesnet.cz>
Michal Vaskoafac7822020-10-20 14:22:26 +02004 * @brief libyang input functions.
Radek Krejcif0e1ba52020-05-22 15:14:35 +02005 *
Michal Vaskoafac7822020-10-20 14:22:26 +02006 * Copyright (c) 2015 - 2020 CESNET, z.s.p.o.
Radek Krejcif0e1ba52020-05-22 15:14:35 +02007 *
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 */
14
15#define _GNU_SOURCE
Radek Krejcif8dc59a2020-11-25 13:47:44 +010016#define _POSIX_C_SOURCE 200809L /* strdup, strndup */
17
18#ifdef __APPLE__
19#define _DARWIN_C_SOURCE /* F_GETPATH */
20#endif
Radek Krejcif0e1ba52020-05-22 15:14:35 +020021
Michal Vaskoafac7822020-10-20 14:22:26 +020022#include "in.h"
23#include "in_internal.h"
Radek Krejcica376bd2020-06-11 16:04:06 +020024
Radek Krejcif0e1ba52020-05-22 15:14:35 +020025#include <errno.h>
26#include <fcntl.h>
27#include <limits.h>
Radek Krejci47fab892020-11-05 17:02:41 +010028#include <stdint.h>
Radek Krejcif0e1ba52020-05-22 15:14:35 +020029#include <stdio.h>
Radek Krejcica376bd2020-06-11 16:04:06 +020030#include <stdlib.h>
Radek Krejcif0e1ba52020-05-22 15:14:35 +020031#include <string.h>
Radek Krejcica376bd2020-06-11 16:04:06 +020032#include <unistd.h>
Radek Krejcif0e1ba52020-05-22 15:14:35 +020033
Radek Krejcica376bd2020-06-11 16:04:06 +020034#include "common.h"
Michal Vasko5aa44c02020-06-29 11:47:02 +020035#include "compat.h"
Radek Krejcica376bd2020-06-11 16:04:06 +020036#include "dict.h"
37#include "log.h"
Radek Krejci1798aae2020-07-14 13:26:06 +020038#include "parser_data.h"
Radek Krejcif0e1ba52020-05-22 15:14:35 +020039#include "parser_internal.h"
Radek Krejci47fab892020-11-05 17:02:41 +010040#include "set.h"
41#include "tree_data.h"
Radek Krejci1798aae2020-07-14 13:26:06 +020042#include "tree_data_internal.h"
Radek Krejci47fab892020-11-05 17:02:41 +010043#include "tree_schema.h"
Radek Krejcica376bd2020-06-11 16:04:06 +020044#include "tree_schema_internal.h"
Radek Krejcif0e1ba52020-05-22 15:14:35 +020045
46API LY_IN_TYPE
47ly_in_type(const struct ly_in *in)
48{
49 LY_CHECK_ARG_RET(NULL, in, LY_IN_ERROR);
50 return in->type;
51}
52
53API LY_ERR
54ly_in_new_fd(int fd, struct ly_in **in)
55{
56 size_t length;
57 char *addr;
58
59 LY_CHECK_ARG_RET(NULL, fd >= 0, in, LY_EINVAL);
60
61 LY_CHECK_RET(ly_mmap(NULL, fd, &length, (void **)&addr));
62 if (!addr) {
63 LOGERR(NULL, LY_EINVAL, "Empty input file.");
64 return LY_EINVAL;
65 }
66
67 *in = calloc(1, sizeof **in);
68 LY_CHECK_ERR_RET(!*in, LOGMEM(NULL); ly_munmap(addr, length), LY_EMEM);
69
70 (*in)->type = LY_IN_FD;
71 (*in)->method.fd = fd;
Michal Vasko63f3d842020-07-08 10:10:14 +020072 (*in)->current = (*in)->start = (*in)->func_start = addr;
Radek Krejcid54412f2020-12-17 20:25:35 +010073 (*in)->line = 1;
Radek Krejcif0e1ba52020-05-22 15:14:35 +020074 (*in)->length = length;
75
76 return LY_SUCCESS;
77}
78
79API int
80ly_in_fd(struct ly_in *in, int fd)
81{
82 int prev_fd;
83 size_t length;
84 const char *addr;
85
86 LY_CHECK_ARG_RET(NULL, in, in->type == LY_IN_FD, -1);
87
88 prev_fd = in->method.fd;
89
90 if (fd != -1) {
91 LY_CHECK_RET(ly_mmap(NULL, fd, &length, (void **)&addr), -1);
92 if (!addr) {
93 LOGERR(NULL, LY_EINVAL, "Empty input file.");
94 return -1;
95 }
96
Michal Vasko22df3f02020-08-24 13:29:22 +020097 ly_munmap((char *)in->start, in->length);
Radek Krejcif0e1ba52020-05-22 15:14:35 +020098
99 in->method.fd = fd;
100 in->current = in->start = addr;
Radek Krejcid54412f2020-12-17 20:25:35 +0100101 in->line = 1;
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200102 in->length = length;
103 }
104
105 return prev_fd;
106}
107
108API LY_ERR
109ly_in_new_file(FILE *f, struct ly_in **in)
110{
111 LY_CHECK_ARG_RET(NULL, f, in, LY_EINVAL);
112
113 LY_CHECK_RET(ly_in_new_fd(fileno(f), in));
114
115 /* convert the LY_IN_FD input handler into the LY_IN_FILE */
116 (*in)->type = LY_IN_FILE;
117 (*in)->method.f = f;
118
119 return LY_SUCCESS;
120}
121
122API FILE *
123ly_in_file(struct ly_in *in, FILE *f)
124{
125 FILE *prev_f;
126
127 LY_CHECK_ARG_RET(NULL, in, in->type == LY_IN_FILE, NULL);
128
129 prev_f = in->method.f;
130
131 if (f) {
132 /* convert LY_IN_FILE handler into LY_IN_FD to be able to update it via ly_in_fd() */
133 in->type = LY_IN_FD;
134 in->method.fd = fileno(prev_f);
135 if (ly_in_fd(in, fileno(f)) == -1) {
136 in->type = LY_IN_FILE;
137 in->method.f = prev_f;
138 return NULL;
139 }
140
141 /* if success, convert the result back */
142 in->type = LY_IN_FILE;
143 in->method.f = f;
144 }
145
146 return prev_f;
147}
148
149API LY_ERR
150ly_in_new_memory(const char *str, struct ly_in **in)
151{
152 LY_CHECK_ARG_RET(NULL, str, in, LY_EINVAL);
153
154 *in = calloc(1, sizeof **in);
155 LY_CHECK_ERR_RET(!*in, LOGMEM(NULL), LY_EMEM);
156
157 (*in)->type = LY_IN_MEMORY;
Michal Vasko63f3d842020-07-08 10:10:14 +0200158 (*in)->start = (*in)->current = (*in)->func_start = str;
Radek Krejcid54412f2020-12-17 20:25:35 +0100159 (*in)->line = 1;
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200160
161 return LY_SUCCESS;
162}
163
Michal Vasko63f3d842020-07-08 10:10:14 +0200164API const char *
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200165ly_in_memory(struct ly_in *in, const char *str)
166{
167 const char *data;
168
169 LY_CHECK_ARG_RET(NULL, in, in->type == LY_IN_MEMORY, NULL);
170
171 data = in->current;
172
173 if (str) {
174 in->start = in->current = str;
Radek Krejcid54412f2020-12-17 20:25:35 +0100175 in->line = 1;
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200176 }
177
178 return data;
179}
180
181API LY_ERR
182ly_in_reset(struct ly_in *in)
183{
184 LY_CHECK_ARG_RET(NULL, in, LY_EINVAL);
185
Michal Vasko63f3d842020-07-08 10:10:14 +0200186 in->current = in->func_start = in->start;
Radek Krejcid54412f2020-12-17 20:25:35 +0100187 in->line = 1;
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200188 return LY_SUCCESS;
189}
190
191API LY_ERR
192ly_in_new_filepath(const char *filepath, size_t len, struct ly_in **in)
193{
Radek Krejci0f969882020-08-21 16:56:47 +0200194 LY_ERR ret;
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200195 char *fp;
196 int fd;
197
198 LY_CHECK_ARG_RET(NULL, filepath, in, LY_EINVAL);
199
200 if (len) {
201 fp = strndup(filepath, len);
202 } else {
203 fp = strdup(filepath);
204 }
205
206 fd = open(fp, O_RDONLY);
Michal Vaskof2eb8af2020-07-14 12:22:40 +0200207 LY_CHECK_ERR_RET(fd == -1, LOGERR(NULL, LY_ESYS, "Failed to open file \"%s\" (%s).", fp, strerror(errno)); free(fp),
Michal Vasko69730152020-10-09 16:30:07 +0200208 LY_ESYS);
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200209
210 LY_CHECK_ERR_RET(ret = ly_in_new_fd(fd, in), free(fp), ret);
211
212 /* convert the LY_IN_FD input handler into the LY_IN_FILE */
213 (*in)->type = LY_IN_FILEPATH;
214 (*in)->method.fpath.fd = fd;
215 (*in)->method.fpath.filepath = fp;
216
217 return LY_SUCCESS;
218}
219
220API const char *
221ly_in_filepath(struct ly_in *in, const char *filepath, size_t len)
222{
223 int fd, prev_fd;
224 char *fp = NULL;
225
226 LY_CHECK_ARG_RET(NULL, in, in->type == LY_IN_FILEPATH, filepath ? NULL : ((void *)-1));
227
228 if (!filepath) {
229 return in->method.fpath.filepath;
230 }
231
232 if (len) {
233 fp = strndup(filepath, len);
234 } else {
235 fp = strdup(filepath);
236 }
237
238 /* replace filepath */
239 fd = open(fp, O_RDONLY);
240 LY_CHECK_ERR_RET(!fd, LOGERR(NULL, LY_ESYS, "Failed to open file \"%s\" (%s).", fp, strerror(errno)); free(fp), NULL);
241
242 /* convert LY_IN_FILEPATH handler into LY_IN_FD to be able to update it via ly_in_fd() */
243 in->type = LY_IN_FD;
244 prev_fd = ly_in_fd(in, fd);
245 LY_CHECK_ERR_RET(prev_fd == -1, in->type = LY_IN_FILEPATH; free(fp), NULL);
246
247 /* and convert the result back */
248 in->type = LY_IN_FILEPATH;
249 close(prev_fd);
250 free(in->method.fpath.filepath);
251 in->method.fpath.fd = fd;
252 in->method.fpath.filepath = fp;
253
254 return NULL;
255}
256
257void
258lys_parser_fill_filepath(struct ly_ctx *ctx, struct ly_in *in, const char **filepath)
259{
260 char path[PATH_MAX];
Michal Vasko69730152020-10-09 16:30:07 +0200261
Michal Vasko5aa44c02020-06-29 11:47:02 +0200262#ifndef __APPLE__
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200263 char proc_path[32];
264 int len;
Michal Vasko5aa44c02020-06-29 11:47:02 +0200265#endif
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200266
267 LY_CHECK_ARG_RET(NULL, ctx, in, filepath, );
268 if (*filepath) {
269 /* filepath already set */
270 return;
271 }
272
273 switch (in->type) {
274 case LY_IN_FILEPATH:
275 if (realpath(in->method.fpath.filepath, path) != NULL) {
Radek Krejci011e4aa2020-09-04 15:22:31 +0200276 lydict_insert(ctx, path, 0, filepath);
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200277 } else {
Radek Krejci011e4aa2020-09-04 15:22:31 +0200278 lydict_insert(ctx, in->method.fpath.filepath, 0, filepath);
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200279 }
280
281 break;
282 case LY_IN_FD:
283#ifdef __APPLE__
284 if (fcntl(in->method.fd, F_GETPATH, path) != -1) {
Radek Krejci011e4aa2020-09-04 15:22:31 +0200285 lydict_insert(ctx, path, 0, filepath);
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200286 }
287#else
288 /* get URI if there is /proc */
289 sprintf(proc_path, "/proc/self/fd/%d", in->method.fd);
290 if ((len = readlink(proc_path, path, PATH_MAX - 1)) > 0) {
Radek Krejci011e4aa2020-09-04 15:22:31 +0200291 lydict_insert(ctx, path, len, filepath);
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200292 }
293#endif
294 break;
295 case LY_IN_MEMORY:
296 case LY_IN_FILE:
297 /* nothing to do */
298 break;
299 default:
300 LOGINT(ctx);
301 break;
302 }
303
304}
305
306API void
Radek Krejci857189e2020-09-01 13:26:36 +0200307ly_in_free(struct ly_in *in, ly_bool destroy)
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200308{
309 if (!in) {
310 return;
311 } else if (in->type == LY_IN_ERROR) {
312 LOGINT(NULL);
313 return;
314 }
315
316 if (destroy) {
317 if (in->type == LY_IN_MEMORY) {
Michal Vasko22df3f02020-08-24 13:29:22 +0200318 free((char *)in->start);
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200319 } else {
Michal Vasko22df3f02020-08-24 13:29:22 +0200320 ly_munmap((char *)in->start, in->length);
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200321
322 if (in->type == LY_IN_FILE) {
323 fclose(in->method.f);
324 } else {
325 close(in->method.fd);
326
327 if (in->type == LY_IN_FILEPATH) {
328 free(in->method.fpath.filepath);
329 }
330 }
331 }
332 } else if (in->type != LY_IN_MEMORY) {
Michal Vasko22df3f02020-08-24 13:29:22 +0200333 ly_munmap((char *)in->start, in->length);
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200334
335 if (in->type == LY_IN_FILEPATH) {
336 close(in->method.fpath.fd);
337 free(in->method.fpath.filepath);
338 }
339 }
340
341 free(in);
342}
Michal Vasko63f3d842020-07-08 10:10:14 +0200343
344LY_ERR
345ly_in_read(struct ly_in *in, void *buf, size_t count)
346{
347 if (in->length && (in->length - (in->current - in->start) < count)) {
348 /* EOF */
349 return LY_EDENIED;
350 }
351
352 memcpy(buf, in->current, count);
353 in->current += count;
354 return LY_SUCCESS;
355}
356
357API size_t
358ly_in_parsed(const struct ly_in *in)
359{
360 return in->current - in->func_start;
361}
362
363LY_ERR
364ly_in_skip(struct ly_in *in, size_t count)
365{
366 if (in->length && (in->length - (in->current - in->start) < count)) {
367 /* EOF */
368 return LY_EDENIED;
369 }
370
371 in->current += count;
372 return LY_SUCCESS;
373}
Radek Krejci1798aae2020-07-14 13:26:06 +0200374
375void
376lyd_ctx_free(struct lyd_ctx *lydctx)
377{
Michal Vasko32711382020-12-03 14:14:31 +0100378 ly_set_erase(&lydctx->node_types, NULL);
379 ly_set_erase(&lydctx->meta_types, NULL);
380 ly_set_erase(&lydctx->node_when, NULL);
Radek Krejci1798aae2020-07-14 13:26:06 +0200381}
382
383LY_ERR
384lyd_parser_check_schema(struct lyd_ctx *lydctx, const struct lysc_node *snode)
385{
Radek Krejci2efc45b2020-12-22 16:25:44 +0100386 LY_ERR ret = LY_EVALID;
387
388 LOG_LOCSET(lydctx->data_ctx->ctx, snode, NULL, NULL, NULL);
Radek Krejci1798aae2020-07-14 13:26:06 +0200389
390 if ((lydctx->parse_options & LYD_PARSE_NO_STATE) && (snode->flags & LYS_CONFIG_R)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100391 LOGVAL(lydctx->data_ctx->ctx, LY_VCODE_INNODE, "state", snode->name);
392 goto cleanup;
Radek Krejci1798aae2020-07-14 13:26:06 +0200393 }
394
395 if (snode->nodetype & (LYS_RPC | LYS_ACTION)) {
Michal Vasko2552ea32020-12-08 15:32:34 +0100396 if (lydctx->int_opts & (LYD_INTOPT_RPC | LYD_INTOPT_REPLY)) {
Radek Krejci1798aae2020-07-14 13:26:06 +0200397 if (lydctx->op_node) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100398 LOGVAL(lydctx->data_ctx->ctx, LYVE_DATA, "Unexpected %s element \"%s\", %s \"%s\" already parsed.",
Michal Vasko69730152020-10-09 16:30:07 +0200399 lys_nodetype2str(snode->nodetype), snode->name,
400 lys_nodetype2str(lydctx->op_node->schema->nodetype), lydctx->op_node->schema->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100401 goto cleanup;
Radek Krejci1798aae2020-07-14 13:26:06 +0200402 }
403 } else {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100404 LOGVAL(lydctx->data_ctx->ctx, LYVE_DATA, "Unexpected %s element \"%s\".",
Michal Vasko69730152020-10-09 16:30:07 +0200405 lys_nodetype2str(snode->nodetype), snode->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100406 goto cleanup;
Radek Krejci1798aae2020-07-14 13:26:06 +0200407 }
408 } else if (snode->nodetype == LYS_NOTIF) {
409 if (lydctx->int_opts & LYD_INTOPT_NOTIF) {
410 if (lydctx->op_node) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100411 LOGVAL(lydctx->data_ctx->ctx, LYVE_DATA, "Unexpected %s element \"%s\", %s \"%s\" already parsed.",
Michal Vasko69730152020-10-09 16:30:07 +0200412 lys_nodetype2str(snode->nodetype), snode->name,
413 lys_nodetype2str(lydctx->op_node->schema->nodetype), lydctx->op_node->schema->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100414 goto cleanup;
Radek Krejci1798aae2020-07-14 13:26:06 +0200415 }
416 } else {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100417 LOGVAL(lydctx->data_ctx->ctx, LYVE_DATA, "Unexpected %s element \"%s\".",
Michal Vasko69730152020-10-09 16:30:07 +0200418 lys_nodetype2str(snode->nodetype), snode->name);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100419 goto cleanup;
Radek Krejci1798aae2020-07-14 13:26:06 +0200420 }
421 }
422
Radek Krejci2efc45b2020-12-22 16:25:44 +0100423 ret = LY_SUCCESS;
424
425cleanup:
426 LOG_LOCBACK(lydctx->data_ctx->ctx, 1, 0, 0, 0);
427 return ret;
Radek Krejci1798aae2020-07-14 13:26:06 +0200428}
429
430LY_ERR
431lyd_parser_create_term(struct lyd_ctx *lydctx, const struct lysc_node *schema, const char *value, size_t value_len,
Michal Vaskofeca4fb2020-10-05 08:58:40 +0200432 ly_bool *dynamic, LY_PREFIX_FORMAT format, void *prefix_data, uint32_t hints, struct lyd_node **node)
Radek Krejci1798aae2020-07-14 13:26:06 +0200433{
Michal Vaskofeca4fb2020-10-05 08:58:40 +0200434 ly_bool incomplete;
Radek Krejci1798aae2020-07-14 13:26:06 +0200435
Michal Vaskofeca4fb2020-10-05 08:58:40 +0200436 LY_CHECK_RET(lyd_create_term(schema, value, value_len, dynamic, format, prefix_data, hints, &incomplete, node));
437
438 if (incomplete && !(lydctx->parse_options & LYD_PARSE_ONLY)) {
Michal Vasko32711382020-12-03 14:14:31 +0100439 LY_CHECK_RET(ly_set_add(&lydctx->node_types, *node, 1, NULL));
Radek Krejci1798aae2020-07-14 13:26:06 +0200440 }
Michal Vaskofeca4fb2020-10-05 08:58:40 +0200441 return LY_SUCCESS;
Radek Krejci1798aae2020-07-14 13:26:06 +0200442}
443
444LY_ERR
445lyd_parser_create_meta(struct lyd_ctx *lydctx, struct lyd_node *parent, struct lyd_meta **meta, const struct lys_module *mod,
Michal Vaskofeca4fb2020-10-05 08:58:40 +0200446 const char *name, size_t name_len, const char *value, size_t value_len, ly_bool *dynamic, LY_PREFIX_FORMAT format,
447 void *prefix_data, uint32_t hints)
Radek Krejci1798aae2020-07-14 13:26:06 +0200448{
Michal Vaskofeca4fb2020-10-05 08:58:40 +0200449 ly_bool incomplete;
Michal Vaskob68571a2020-11-06 17:18:41 +0100450 struct lyd_meta *first = NULL;
451
452 if (meta && *meta) {
453 /* remember the first metadata */
454 first = *meta;
455 }
Michal Vaskofeca4fb2020-10-05 08:58:40 +0200456
457 LY_CHECK_RET(lyd_create_meta(parent, meta, mod, name, name_len, value, value_len, dynamic, format, prefix_data,
Michal Vasko871a0252020-11-11 18:35:24 +0100458 hints, 0, &incomplete));
Michal Vaskofeca4fb2020-10-05 08:58:40 +0200459
460 if (incomplete && !(lydctx->parse_options & LYD_PARSE_ONLY)) {
Michal Vasko32711382020-12-03 14:14:31 +0100461 LY_CHECK_RET(ly_set_add(&lydctx->meta_types, *meta, 1, NULL));
Radek Krejci1798aae2020-07-14 13:26:06 +0200462 }
Michal Vaskob68571a2020-11-06 17:18:41 +0100463
464 if (first) {
465 /* always return the first metadata */
466 *meta = first;
467 }
468
Michal Vaskofeca4fb2020-10-05 08:58:40 +0200469 return LY_SUCCESS;
Radek Krejci1798aae2020-07-14 13:26:06 +0200470}