blob: f8020101b96b7f3431814b0c5915f4492d4f5a9f [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
16
Michal Vaskoafac7822020-10-20 14:22:26 +020017#include "in.h"
18#include "in_internal.h"
Radek Krejcica376bd2020-06-11 16:04:06 +020019
Radek Krejcif0e1ba52020-05-22 15:14:35 +020020#include <errno.h>
21#include <fcntl.h>
22#include <limits.h>
Radek Krejci47fab892020-11-05 17:02:41 +010023#include <stdint.h>
Radek Krejcif0e1ba52020-05-22 15:14:35 +020024#include <stdio.h>
Radek Krejcica376bd2020-06-11 16:04:06 +020025#include <stdlib.h>
Radek Krejcif0e1ba52020-05-22 15:14:35 +020026#include <string.h>
Radek Krejcica376bd2020-06-11 16:04:06 +020027#include <unistd.h>
Radek Krejcif0e1ba52020-05-22 15:14:35 +020028
Radek Krejcica376bd2020-06-11 16:04:06 +020029#include "common.h"
Michal Vasko5aa44c02020-06-29 11:47:02 +020030#include "compat.h"
Radek Krejcica376bd2020-06-11 16:04:06 +020031#include "dict.h"
32#include "log.h"
Radek Krejci1798aae2020-07-14 13:26:06 +020033#include "parser_data.h"
Radek Krejcif0e1ba52020-05-22 15:14:35 +020034#include "parser_internal.h"
Radek Krejci47fab892020-11-05 17:02:41 +010035#include "set.h"
36#include "tree_data.h"
Radek Krejci1798aae2020-07-14 13:26:06 +020037#include "tree_data_internal.h"
Radek Krejci47fab892020-11-05 17:02:41 +010038#include "tree_schema.h"
Radek Krejcica376bd2020-06-11 16:04:06 +020039#include "tree_schema_internal.h"
Radek Krejcif0e1ba52020-05-22 15:14:35 +020040
41API LY_IN_TYPE
42ly_in_type(const struct ly_in *in)
43{
44 LY_CHECK_ARG_RET(NULL, in, LY_IN_ERROR);
45 return in->type;
46}
47
48API LY_ERR
49ly_in_new_fd(int fd, struct ly_in **in)
50{
51 size_t length;
52 char *addr;
53
54 LY_CHECK_ARG_RET(NULL, fd >= 0, in, LY_EINVAL);
55
56 LY_CHECK_RET(ly_mmap(NULL, fd, &length, (void **)&addr));
57 if (!addr) {
58 LOGERR(NULL, LY_EINVAL, "Empty input file.");
59 return LY_EINVAL;
60 }
61
62 *in = calloc(1, sizeof **in);
63 LY_CHECK_ERR_RET(!*in, LOGMEM(NULL); ly_munmap(addr, length), LY_EMEM);
64
65 (*in)->type = LY_IN_FD;
66 (*in)->method.fd = fd;
Michal Vasko63f3d842020-07-08 10:10:14 +020067 (*in)->current = (*in)->start = (*in)->func_start = addr;
Radek Krejcif0e1ba52020-05-22 15:14:35 +020068 (*in)->length = length;
69
70 return LY_SUCCESS;
71}
72
73API int
74ly_in_fd(struct ly_in *in, int fd)
75{
76 int prev_fd;
77 size_t length;
78 const char *addr;
79
80 LY_CHECK_ARG_RET(NULL, in, in->type == LY_IN_FD, -1);
81
82 prev_fd = in->method.fd;
83
84 if (fd != -1) {
85 LY_CHECK_RET(ly_mmap(NULL, fd, &length, (void **)&addr), -1);
86 if (!addr) {
87 LOGERR(NULL, LY_EINVAL, "Empty input file.");
88 return -1;
89 }
90
Michal Vasko22df3f02020-08-24 13:29:22 +020091 ly_munmap((char *)in->start, in->length);
Radek Krejcif0e1ba52020-05-22 15:14:35 +020092
93 in->method.fd = fd;
94 in->current = in->start = addr;
95 in->length = length;
96 }
97
98 return prev_fd;
99}
100
101API LY_ERR
102ly_in_new_file(FILE *f, struct ly_in **in)
103{
104 LY_CHECK_ARG_RET(NULL, f, in, LY_EINVAL);
105
106 LY_CHECK_RET(ly_in_new_fd(fileno(f), in));
107
108 /* convert the LY_IN_FD input handler into the LY_IN_FILE */
109 (*in)->type = LY_IN_FILE;
110 (*in)->method.f = f;
111
112 return LY_SUCCESS;
113}
114
115API FILE *
116ly_in_file(struct ly_in *in, FILE *f)
117{
118 FILE *prev_f;
119
120 LY_CHECK_ARG_RET(NULL, in, in->type == LY_IN_FILE, NULL);
121
122 prev_f = in->method.f;
123
124 if (f) {
125 /* convert LY_IN_FILE handler into LY_IN_FD to be able to update it via ly_in_fd() */
126 in->type = LY_IN_FD;
127 in->method.fd = fileno(prev_f);
128 if (ly_in_fd(in, fileno(f)) == -1) {
129 in->type = LY_IN_FILE;
130 in->method.f = prev_f;
131 return NULL;
132 }
133
134 /* if success, convert the result back */
135 in->type = LY_IN_FILE;
136 in->method.f = f;
137 }
138
139 return prev_f;
140}
141
142API LY_ERR
143ly_in_new_memory(const char *str, struct ly_in **in)
144{
145 LY_CHECK_ARG_RET(NULL, str, in, LY_EINVAL);
146
147 *in = calloc(1, sizeof **in);
148 LY_CHECK_ERR_RET(!*in, LOGMEM(NULL), LY_EMEM);
149
150 (*in)->type = LY_IN_MEMORY;
Michal Vasko63f3d842020-07-08 10:10:14 +0200151 (*in)->start = (*in)->current = (*in)->func_start = str;
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200152
153 return LY_SUCCESS;
154}
155
Michal Vasko63f3d842020-07-08 10:10:14 +0200156API const char *
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200157ly_in_memory(struct ly_in *in, const char *str)
158{
159 const char *data;
160
161 LY_CHECK_ARG_RET(NULL, in, in->type == LY_IN_MEMORY, NULL);
162
163 data = in->current;
164
165 if (str) {
166 in->start = in->current = str;
167 }
168
169 return data;
170}
171
172API LY_ERR
173ly_in_reset(struct ly_in *in)
174{
175 LY_CHECK_ARG_RET(NULL, in, LY_EINVAL);
176
Michal Vasko63f3d842020-07-08 10:10:14 +0200177 in->current = in->func_start = in->start;
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200178 return LY_SUCCESS;
179}
180
181API LY_ERR
182ly_in_new_filepath(const char *filepath, size_t len, struct ly_in **in)
183{
Radek Krejci0f969882020-08-21 16:56:47 +0200184 LY_ERR ret;
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200185 char *fp;
186 int fd;
187
188 LY_CHECK_ARG_RET(NULL, filepath, in, LY_EINVAL);
189
190 if (len) {
191 fp = strndup(filepath, len);
192 } else {
193 fp = strdup(filepath);
194 }
195
196 fd = open(fp, O_RDONLY);
Michal Vaskof2eb8af2020-07-14 12:22:40 +0200197 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 +0200198 LY_ESYS);
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200199
200 LY_CHECK_ERR_RET(ret = ly_in_new_fd(fd, in), free(fp), ret);
201
202 /* convert the LY_IN_FD input handler into the LY_IN_FILE */
203 (*in)->type = LY_IN_FILEPATH;
204 (*in)->method.fpath.fd = fd;
205 (*in)->method.fpath.filepath = fp;
206
207 return LY_SUCCESS;
208}
209
210API const char *
211ly_in_filepath(struct ly_in *in, const char *filepath, size_t len)
212{
213 int fd, prev_fd;
214 char *fp = NULL;
215
216 LY_CHECK_ARG_RET(NULL, in, in->type == LY_IN_FILEPATH, filepath ? NULL : ((void *)-1));
217
218 if (!filepath) {
219 return in->method.fpath.filepath;
220 }
221
222 if (len) {
223 fp = strndup(filepath, len);
224 } else {
225 fp = strdup(filepath);
226 }
227
228 /* replace filepath */
229 fd = open(fp, O_RDONLY);
230 LY_CHECK_ERR_RET(!fd, LOGERR(NULL, LY_ESYS, "Failed to open file \"%s\" (%s).", fp, strerror(errno)); free(fp), NULL);
231
232 /* convert LY_IN_FILEPATH handler into LY_IN_FD to be able to update it via ly_in_fd() */
233 in->type = LY_IN_FD;
234 prev_fd = ly_in_fd(in, fd);
235 LY_CHECK_ERR_RET(prev_fd == -1, in->type = LY_IN_FILEPATH; free(fp), NULL);
236
237 /* and convert the result back */
238 in->type = LY_IN_FILEPATH;
239 close(prev_fd);
240 free(in->method.fpath.filepath);
241 in->method.fpath.fd = fd;
242 in->method.fpath.filepath = fp;
243
244 return NULL;
245}
246
247void
248lys_parser_fill_filepath(struct ly_ctx *ctx, struct ly_in *in, const char **filepath)
249{
250 char path[PATH_MAX];
Michal Vasko69730152020-10-09 16:30:07 +0200251
Michal Vasko5aa44c02020-06-29 11:47:02 +0200252#ifndef __APPLE__
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200253 char proc_path[32];
254 int len;
Michal Vasko5aa44c02020-06-29 11:47:02 +0200255#endif
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200256
257 LY_CHECK_ARG_RET(NULL, ctx, in, filepath, );
258 if (*filepath) {
259 /* filepath already set */
260 return;
261 }
262
263 switch (in->type) {
264 case LY_IN_FILEPATH:
265 if (realpath(in->method.fpath.filepath, path) != NULL) {
Radek Krejci011e4aa2020-09-04 15:22:31 +0200266 lydict_insert(ctx, path, 0, filepath);
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200267 } else {
Radek Krejci011e4aa2020-09-04 15:22:31 +0200268 lydict_insert(ctx, in->method.fpath.filepath, 0, filepath);
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200269 }
270
271 break;
272 case LY_IN_FD:
273#ifdef __APPLE__
274 if (fcntl(in->method.fd, F_GETPATH, path) != -1) {
Radek Krejci011e4aa2020-09-04 15:22:31 +0200275 lydict_insert(ctx, path, 0, filepath);
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200276 }
277#else
278 /* get URI if there is /proc */
279 sprintf(proc_path, "/proc/self/fd/%d", in->method.fd);
280 if ((len = readlink(proc_path, path, PATH_MAX - 1)) > 0) {
Radek Krejci011e4aa2020-09-04 15:22:31 +0200281 lydict_insert(ctx, path, len, filepath);
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200282 }
283#endif
284 break;
285 case LY_IN_MEMORY:
286 case LY_IN_FILE:
287 /* nothing to do */
288 break;
289 default:
290 LOGINT(ctx);
291 break;
292 }
293
294}
295
296API void
Radek Krejci857189e2020-09-01 13:26:36 +0200297ly_in_free(struct ly_in *in, ly_bool destroy)
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200298{
299 if (!in) {
300 return;
301 } else if (in->type == LY_IN_ERROR) {
302 LOGINT(NULL);
303 return;
304 }
305
306 if (destroy) {
307 if (in->type == LY_IN_MEMORY) {
Michal Vasko22df3f02020-08-24 13:29:22 +0200308 free((char *)in->start);
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200309 } else {
Michal Vasko22df3f02020-08-24 13:29:22 +0200310 ly_munmap((char *)in->start, in->length);
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200311
312 if (in->type == LY_IN_FILE) {
313 fclose(in->method.f);
314 } else {
315 close(in->method.fd);
316
317 if (in->type == LY_IN_FILEPATH) {
318 free(in->method.fpath.filepath);
319 }
320 }
321 }
322 } else if (in->type != LY_IN_MEMORY) {
Michal Vasko22df3f02020-08-24 13:29:22 +0200323 ly_munmap((char *)in->start, in->length);
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200324
325 if (in->type == LY_IN_FILEPATH) {
326 close(in->method.fpath.fd);
327 free(in->method.fpath.filepath);
328 }
329 }
330
331 free(in);
332}
Michal Vasko63f3d842020-07-08 10:10:14 +0200333
334LY_ERR
335ly_in_read(struct ly_in *in, void *buf, size_t count)
336{
337 if (in->length && (in->length - (in->current - in->start) < count)) {
338 /* EOF */
339 return LY_EDENIED;
340 }
341
342 memcpy(buf, in->current, count);
343 in->current += count;
344 return LY_SUCCESS;
345}
346
347API size_t
348ly_in_parsed(const struct ly_in *in)
349{
350 return in->current - in->func_start;
351}
352
353LY_ERR
354ly_in_skip(struct ly_in *in, size_t count)
355{
356 if (in->length && (in->length - (in->current - in->start) < count)) {
357 /* EOF */
358 return LY_EDENIED;
359 }
360
361 in->current += count;
362 return LY_SUCCESS;
363}
Radek Krejci1798aae2020-07-14 13:26:06 +0200364
365void
366lyd_ctx_free(struct lyd_ctx *lydctx)
367{
368 ly_set_erase(&lydctx->unres_node_type, NULL);
369 ly_set_erase(&lydctx->unres_meta_type, NULL);
370 ly_set_erase(&lydctx->when_check, NULL);
371}
372
373LY_ERR
374lyd_parser_check_schema(struct lyd_ctx *lydctx, const struct lysc_node *snode)
375{
376 /* alternatively, we could provide line for the error messages, but it doesn't work for the LYB format */
377
378 if ((lydctx->parse_options & LYD_PARSE_NO_STATE) && (snode->flags & LYS_CONFIG_R)) {
379 LOGVAL(lydctx->data_ctx->ctx, LY_VLOG_LYSC, snode, LY_VCODE_INNODE, "state", snode->name);
380 return LY_EVALID;
381 }
382
383 if (snode->nodetype & (LYS_RPC | LYS_ACTION)) {
384 if (lydctx->int_opts & LYD_INTOPT_RPC) {
385 if (lydctx->op_node) {
386 LOGVAL(lydctx->data_ctx->ctx, LY_VLOG_LYSC, snode, LYVE_DATA, "Unexpected %s element \"%s\", %s \"%s\" already parsed.",
Michal Vasko69730152020-10-09 16:30:07 +0200387 lys_nodetype2str(snode->nodetype), snode->name,
388 lys_nodetype2str(lydctx->op_node->schema->nodetype), lydctx->op_node->schema->name);
Radek Krejci1798aae2020-07-14 13:26:06 +0200389 return LY_EVALID;
390 }
391 } else {
392 LOGVAL(lydctx->data_ctx->ctx, LY_VLOG_LYSC, snode, LYVE_DATA, "Unexpected %s element \"%s\".",
Michal Vasko69730152020-10-09 16:30:07 +0200393 lys_nodetype2str(snode->nodetype), snode->name);
Radek Krejci1798aae2020-07-14 13:26:06 +0200394 return LY_EVALID;
395 }
396 } else if (snode->nodetype == LYS_NOTIF) {
397 if (lydctx->int_opts & LYD_INTOPT_NOTIF) {
398 if (lydctx->op_node) {
399 LOGVAL(lydctx->data_ctx->ctx, LY_VLOG_LYSC, snode, LYVE_DATA, "Unexpected %s element \"%s\", %s \"%s\" already parsed.",
Michal Vasko69730152020-10-09 16:30:07 +0200400 lys_nodetype2str(snode->nodetype), snode->name,
401 lys_nodetype2str(lydctx->op_node->schema->nodetype), lydctx->op_node->schema->name);
Radek Krejci1798aae2020-07-14 13:26:06 +0200402 return LY_EVALID;
403 }
404 } else {
405 LOGVAL(lydctx->data_ctx->ctx, LY_VLOG_LYSC, snode, LYVE_DATA, "Unexpected %s element \"%s\".",
Michal Vasko69730152020-10-09 16:30:07 +0200406 lys_nodetype2str(snode->nodetype), snode->name);
Radek Krejci1798aae2020-07-14 13:26:06 +0200407 return LY_EVALID;
408 }
409 }
410
411 return LY_SUCCESS;
412}
413
414LY_ERR
415lyd_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 +0200416 ly_bool *dynamic, LY_PREFIX_FORMAT format, void *prefix_data, uint32_t hints, struct lyd_node **node)
Radek Krejci1798aae2020-07-14 13:26:06 +0200417{
Michal Vaskofeca4fb2020-10-05 08:58:40 +0200418 ly_bool incomplete;
Radek Krejci1798aae2020-07-14 13:26:06 +0200419
Michal Vaskofeca4fb2020-10-05 08:58:40 +0200420 LY_CHECK_RET(lyd_create_term(schema, value, value_len, dynamic, format, prefix_data, hints, &incomplete, node));
421
422 if (incomplete && !(lydctx->parse_options & LYD_PARSE_ONLY)) {
Radek Krejci3d92e442020-10-12 12:48:13 +0200423 LY_CHECK_RET(ly_set_add(&lydctx->unres_node_type, *node, 1, NULL));
Radek Krejci1798aae2020-07-14 13:26:06 +0200424 }
Michal Vaskofeca4fb2020-10-05 08:58:40 +0200425 return LY_SUCCESS;
Radek Krejci1798aae2020-07-14 13:26:06 +0200426}
427
428LY_ERR
429lyd_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 +0200430 const char *name, size_t name_len, const char *value, size_t value_len, ly_bool *dynamic, LY_PREFIX_FORMAT format,
431 void *prefix_data, uint32_t hints)
Radek Krejci1798aae2020-07-14 13:26:06 +0200432{
Michal Vaskofeca4fb2020-10-05 08:58:40 +0200433 ly_bool incomplete;
Michal Vaskob68571a2020-11-06 17:18:41 +0100434 struct lyd_meta *first = NULL;
435
436 if (meta && *meta) {
437 /* remember the first metadata */
438 first = *meta;
439 }
Michal Vaskofeca4fb2020-10-05 08:58:40 +0200440
441 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 +0100442 hints, 0, &incomplete));
Michal Vaskofeca4fb2020-10-05 08:58:40 +0200443
444 if (incomplete && !(lydctx->parse_options & LYD_PARSE_ONLY)) {
Radek Krejci3d92e442020-10-12 12:48:13 +0200445 LY_CHECK_RET(ly_set_add(&lydctx->unres_meta_type, *meta, 1, NULL));
Radek Krejci1798aae2020-07-14 13:26:06 +0200446 }
Michal Vaskob68571a2020-11-06 17:18:41 +0100447
448 if (first) {
449 /* always return the first metadata */
450 *meta = first;
451 }
452
Michal Vaskofeca4fb2020-10-05 08:58:40 +0200453 return LY_SUCCESS;
Radek Krejci1798aae2020-07-14 13:26:06 +0200454}