blob: f20195ec01b3478e78e01229adee741edf055fb3 [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>
23#include <stdio.h>
Radek Krejcica376bd2020-06-11 16:04:06 +020024#include <stdlib.h>
Radek Krejcif0e1ba52020-05-22 15:14:35 +020025#include <string.h>
Radek Krejcica376bd2020-06-11 16:04:06 +020026#include <unistd.h>
Radek Krejcif0e1ba52020-05-22 15:14:35 +020027
Radek Krejcica376bd2020-06-11 16:04:06 +020028#include "common.h"
Michal Vasko5aa44c02020-06-29 11:47:02 +020029#include "compat.h"
Radek Krejcica376bd2020-06-11 16:04:06 +020030#include "dict.h"
31#include "log.h"
Radek Krejci1798aae2020-07-14 13:26:06 +020032#include "parser_data.h"
Radek Krejcif0e1ba52020-05-22 15:14:35 +020033#include "parser_internal.h"
Radek Krejci1798aae2020-07-14 13:26:06 +020034#include "tree_data_internal.h"
Radek Krejcica376bd2020-06-11 16:04:06 +020035#include "tree_schema_internal.h"
Radek Krejcif0e1ba52020-05-22 15:14:35 +020036
37API LY_IN_TYPE
38ly_in_type(const struct ly_in *in)
39{
40 LY_CHECK_ARG_RET(NULL, in, LY_IN_ERROR);
41 return in->type;
42}
43
44API LY_ERR
45ly_in_new_fd(int fd, struct ly_in **in)
46{
47 size_t length;
48 char *addr;
49
50 LY_CHECK_ARG_RET(NULL, fd >= 0, in, LY_EINVAL);
51
52 LY_CHECK_RET(ly_mmap(NULL, fd, &length, (void **)&addr));
53 if (!addr) {
54 LOGERR(NULL, LY_EINVAL, "Empty input file.");
55 return LY_EINVAL;
56 }
57
58 *in = calloc(1, sizeof **in);
59 LY_CHECK_ERR_RET(!*in, LOGMEM(NULL); ly_munmap(addr, length), LY_EMEM);
60
61 (*in)->type = LY_IN_FD;
62 (*in)->method.fd = fd;
Michal Vasko63f3d842020-07-08 10:10:14 +020063 (*in)->current = (*in)->start = (*in)->func_start = addr;
Radek Krejcif0e1ba52020-05-22 15:14:35 +020064 (*in)->length = length;
65
66 return LY_SUCCESS;
67}
68
69API int
70ly_in_fd(struct ly_in *in, int fd)
71{
72 int prev_fd;
73 size_t length;
74 const char *addr;
75
76 LY_CHECK_ARG_RET(NULL, in, in->type == LY_IN_FD, -1);
77
78 prev_fd = in->method.fd;
79
80 if (fd != -1) {
81 LY_CHECK_RET(ly_mmap(NULL, fd, &length, (void **)&addr), -1);
82 if (!addr) {
83 LOGERR(NULL, LY_EINVAL, "Empty input file.");
84 return -1;
85 }
86
Michal Vasko22df3f02020-08-24 13:29:22 +020087 ly_munmap((char *)in->start, in->length);
Radek Krejcif0e1ba52020-05-22 15:14:35 +020088
89 in->method.fd = fd;
90 in->current = in->start = addr;
91 in->length = length;
92 }
93
94 return prev_fd;
95}
96
97API LY_ERR
98ly_in_new_file(FILE *f, struct ly_in **in)
99{
100 LY_CHECK_ARG_RET(NULL, f, in, LY_EINVAL);
101
102 LY_CHECK_RET(ly_in_new_fd(fileno(f), in));
103
104 /* convert the LY_IN_FD input handler into the LY_IN_FILE */
105 (*in)->type = LY_IN_FILE;
106 (*in)->method.f = f;
107
108 return LY_SUCCESS;
109}
110
111API FILE *
112ly_in_file(struct ly_in *in, FILE *f)
113{
114 FILE *prev_f;
115
116 LY_CHECK_ARG_RET(NULL, in, in->type == LY_IN_FILE, NULL);
117
118 prev_f = in->method.f;
119
120 if (f) {
121 /* convert LY_IN_FILE handler into LY_IN_FD to be able to update it via ly_in_fd() */
122 in->type = LY_IN_FD;
123 in->method.fd = fileno(prev_f);
124 if (ly_in_fd(in, fileno(f)) == -1) {
125 in->type = LY_IN_FILE;
126 in->method.f = prev_f;
127 return NULL;
128 }
129
130 /* if success, convert the result back */
131 in->type = LY_IN_FILE;
132 in->method.f = f;
133 }
134
135 return prev_f;
136}
137
138API LY_ERR
139ly_in_new_memory(const char *str, struct ly_in **in)
140{
141 LY_CHECK_ARG_RET(NULL, str, in, LY_EINVAL);
142
143 *in = calloc(1, sizeof **in);
144 LY_CHECK_ERR_RET(!*in, LOGMEM(NULL), LY_EMEM);
145
146 (*in)->type = LY_IN_MEMORY;
Michal Vasko63f3d842020-07-08 10:10:14 +0200147 (*in)->start = (*in)->current = (*in)->func_start = str;
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200148
149 return LY_SUCCESS;
150}
151
Michal Vasko63f3d842020-07-08 10:10:14 +0200152API const char *
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200153ly_in_memory(struct ly_in *in, const char *str)
154{
155 const char *data;
156
157 LY_CHECK_ARG_RET(NULL, in, in->type == LY_IN_MEMORY, NULL);
158
159 data = in->current;
160
161 if (str) {
162 in->start = in->current = str;
163 }
164
165 return data;
166}
167
168API LY_ERR
169ly_in_reset(struct ly_in *in)
170{
171 LY_CHECK_ARG_RET(NULL, in, LY_EINVAL);
172
Michal Vasko63f3d842020-07-08 10:10:14 +0200173 in->current = in->func_start = in->start;
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200174 return LY_SUCCESS;
175}
176
177API LY_ERR
178ly_in_new_filepath(const char *filepath, size_t len, struct ly_in **in)
179{
Radek Krejci0f969882020-08-21 16:56:47 +0200180 LY_ERR ret;
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200181 char *fp;
182 int fd;
183
184 LY_CHECK_ARG_RET(NULL, filepath, in, LY_EINVAL);
185
186 if (len) {
187 fp = strndup(filepath, len);
188 } else {
189 fp = strdup(filepath);
190 }
191
192 fd = open(fp, O_RDONLY);
Michal Vaskof2eb8af2020-07-14 12:22:40 +0200193 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 +0200194 LY_ESYS);
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200195
196 LY_CHECK_ERR_RET(ret = ly_in_new_fd(fd, in), free(fp), ret);
197
198 /* convert the LY_IN_FD input handler into the LY_IN_FILE */
199 (*in)->type = LY_IN_FILEPATH;
200 (*in)->method.fpath.fd = fd;
201 (*in)->method.fpath.filepath = fp;
202
203 return LY_SUCCESS;
204}
205
206API const char *
207ly_in_filepath(struct ly_in *in, const char *filepath, size_t len)
208{
209 int fd, prev_fd;
210 char *fp = NULL;
211
212 LY_CHECK_ARG_RET(NULL, in, in->type == LY_IN_FILEPATH, filepath ? NULL : ((void *)-1));
213
214 if (!filepath) {
215 return in->method.fpath.filepath;
216 }
217
218 if (len) {
219 fp = strndup(filepath, len);
220 } else {
221 fp = strdup(filepath);
222 }
223
224 /* replace filepath */
225 fd = open(fp, O_RDONLY);
226 LY_CHECK_ERR_RET(!fd, LOGERR(NULL, LY_ESYS, "Failed to open file \"%s\" (%s).", fp, strerror(errno)); free(fp), NULL);
227
228 /* convert LY_IN_FILEPATH handler into LY_IN_FD to be able to update it via ly_in_fd() */
229 in->type = LY_IN_FD;
230 prev_fd = ly_in_fd(in, fd);
231 LY_CHECK_ERR_RET(prev_fd == -1, in->type = LY_IN_FILEPATH; free(fp), NULL);
232
233 /* and convert the result back */
234 in->type = LY_IN_FILEPATH;
235 close(prev_fd);
236 free(in->method.fpath.filepath);
237 in->method.fpath.fd = fd;
238 in->method.fpath.filepath = fp;
239
240 return NULL;
241}
242
243void
244lys_parser_fill_filepath(struct ly_ctx *ctx, struct ly_in *in, const char **filepath)
245{
246 char path[PATH_MAX];
Michal Vasko69730152020-10-09 16:30:07 +0200247
Michal Vasko5aa44c02020-06-29 11:47:02 +0200248#ifndef __APPLE__
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200249 char proc_path[32];
250 int len;
Michal Vasko5aa44c02020-06-29 11:47:02 +0200251#endif
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200252
253 LY_CHECK_ARG_RET(NULL, ctx, in, filepath, );
254 if (*filepath) {
255 /* filepath already set */
256 return;
257 }
258
259 switch (in->type) {
260 case LY_IN_FILEPATH:
261 if (realpath(in->method.fpath.filepath, path) != NULL) {
Radek Krejci011e4aa2020-09-04 15:22:31 +0200262 lydict_insert(ctx, path, 0, filepath);
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200263 } else {
Radek Krejci011e4aa2020-09-04 15:22:31 +0200264 lydict_insert(ctx, in->method.fpath.filepath, 0, filepath);
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200265 }
266
267 break;
268 case LY_IN_FD:
269#ifdef __APPLE__
270 if (fcntl(in->method.fd, F_GETPATH, path) != -1) {
Radek Krejci011e4aa2020-09-04 15:22:31 +0200271 lydict_insert(ctx, path, 0, filepath);
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200272 }
273#else
274 /* get URI if there is /proc */
275 sprintf(proc_path, "/proc/self/fd/%d", in->method.fd);
276 if ((len = readlink(proc_path, path, PATH_MAX - 1)) > 0) {
Radek Krejci011e4aa2020-09-04 15:22:31 +0200277 lydict_insert(ctx, path, len, filepath);
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200278 }
279#endif
280 break;
281 case LY_IN_MEMORY:
282 case LY_IN_FILE:
283 /* nothing to do */
284 break;
285 default:
286 LOGINT(ctx);
287 break;
288 }
289
290}
291
292API void
Radek Krejci857189e2020-09-01 13:26:36 +0200293ly_in_free(struct ly_in *in, ly_bool destroy)
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200294{
295 if (!in) {
296 return;
297 } else if (in->type == LY_IN_ERROR) {
298 LOGINT(NULL);
299 return;
300 }
301
302 if (destroy) {
303 if (in->type == LY_IN_MEMORY) {
Michal Vasko22df3f02020-08-24 13:29:22 +0200304 free((char *)in->start);
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200305 } else {
Michal Vasko22df3f02020-08-24 13:29:22 +0200306 ly_munmap((char *)in->start, in->length);
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200307
308 if (in->type == LY_IN_FILE) {
309 fclose(in->method.f);
310 } else {
311 close(in->method.fd);
312
313 if (in->type == LY_IN_FILEPATH) {
314 free(in->method.fpath.filepath);
315 }
316 }
317 }
318 } else if (in->type != LY_IN_MEMORY) {
Michal Vasko22df3f02020-08-24 13:29:22 +0200319 ly_munmap((char *)in->start, in->length);
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200320
321 if (in->type == LY_IN_FILEPATH) {
322 close(in->method.fpath.fd);
323 free(in->method.fpath.filepath);
324 }
325 }
326
327 free(in);
328}
Michal Vasko63f3d842020-07-08 10:10:14 +0200329
330LY_ERR
331ly_in_read(struct ly_in *in, void *buf, size_t count)
332{
333 if (in->length && (in->length - (in->current - in->start) < count)) {
334 /* EOF */
335 return LY_EDENIED;
336 }
337
338 memcpy(buf, in->current, count);
339 in->current += count;
340 return LY_SUCCESS;
341}
342
343API size_t
344ly_in_parsed(const struct ly_in *in)
345{
346 return in->current - in->func_start;
347}
348
349LY_ERR
350ly_in_skip(struct ly_in *in, size_t count)
351{
352 if (in->length && (in->length - (in->current - in->start) < count)) {
353 /* EOF */
354 return LY_EDENIED;
355 }
356
357 in->current += count;
358 return LY_SUCCESS;
359}
Radek Krejci1798aae2020-07-14 13:26:06 +0200360
361void
362lyd_ctx_free(struct lyd_ctx *lydctx)
363{
364 ly_set_erase(&lydctx->unres_node_type, NULL);
365 ly_set_erase(&lydctx->unres_meta_type, NULL);
366 ly_set_erase(&lydctx->when_check, NULL);
367}
368
369LY_ERR
370lyd_parser_check_schema(struct lyd_ctx *lydctx, const struct lysc_node *snode)
371{
372 /* alternatively, we could provide line for the error messages, but it doesn't work for the LYB format */
373
374 if ((lydctx->parse_options & LYD_PARSE_NO_STATE) && (snode->flags & LYS_CONFIG_R)) {
375 LOGVAL(lydctx->data_ctx->ctx, LY_VLOG_LYSC, snode, LY_VCODE_INNODE, "state", snode->name);
376 return LY_EVALID;
377 }
378
379 if (snode->nodetype & (LYS_RPC | LYS_ACTION)) {
380 if (lydctx->int_opts & LYD_INTOPT_RPC) {
381 if (lydctx->op_node) {
382 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 +0200383 lys_nodetype2str(snode->nodetype), snode->name,
384 lys_nodetype2str(lydctx->op_node->schema->nodetype), lydctx->op_node->schema->name);
Radek Krejci1798aae2020-07-14 13:26:06 +0200385 return LY_EVALID;
386 }
387 } else {
388 LOGVAL(lydctx->data_ctx->ctx, LY_VLOG_LYSC, snode, LYVE_DATA, "Unexpected %s element \"%s\".",
Michal Vasko69730152020-10-09 16:30:07 +0200389 lys_nodetype2str(snode->nodetype), snode->name);
Radek Krejci1798aae2020-07-14 13:26:06 +0200390 return LY_EVALID;
391 }
392 } else if (snode->nodetype == LYS_NOTIF) {
393 if (lydctx->int_opts & LYD_INTOPT_NOTIF) {
394 if (lydctx->op_node) {
395 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 +0200396 lys_nodetype2str(snode->nodetype), snode->name,
397 lys_nodetype2str(lydctx->op_node->schema->nodetype), lydctx->op_node->schema->name);
Radek Krejci1798aae2020-07-14 13:26:06 +0200398 return LY_EVALID;
399 }
400 } else {
401 LOGVAL(lydctx->data_ctx->ctx, LY_VLOG_LYSC, snode, LYVE_DATA, "Unexpected %s element \"%s\".",
Michal Vasko69730152020-10-09 16:30:07 +0200402 lys_nodetype2str(snode->nodetype), snode->name);
Radek Krejci1798aae2020-07-14 13:26:06 +0200403 return LY_EVALID;
404 }
405 }
406
407 return LY_SUCCESS;
408}
409
410LY_ERR
411lyd_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 +0200412 ly_bool *dynamic, LY_PREFIX_FORMAT format, void *prefix_data, uint32_t hints, struct lyd_node **node)
Radek Krejci1798aae2020-07-14 13:26:06 +0200413{
Michal Vaskofeca4fb2020-10-05 08:58:40 +0200414 ly_bool incomplete;
Radek Krejci1798aae2020-07-14 13:26:06 +0200415
Michal Vaskofeca4fb2020-10-05 08:58:40 +0200416 LY_CHECK_RET(lyd_create_term(schema, value, value_len, dynamic, format, prefix_data, hints, &incomplete, node));
417
418 if (incomplete && !(lydctx->parse_options & LYD_PARSE_ONLY)) {
Radek Krejci3d92e442020-10-12 12:48:13 +0200419 LY_CHECK_RET(ly_set_add(&lydctx->unres_node_type, *node, 1, NULL));
Radek Krejci1798aae2020-07-14 13:26:06 +0200420 }
Michal Vaskofeca4fb2020-10-05 08:58:40 +0200421 return LY_SUCCESS;
Radek Krejci1798aae2020-07-14 13:26:06 +0200422}
423
424LY_ERR
425lyd_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 +0200426 const char *name, size_t name_len, const char *value, size_t value_len, ly_bool *dynamic, LY_PREFIX_FORMAT format,
427 void *prefix_data, uint32_t hints)
Radek Krejci1798aae2020-07-14 13:26:06 +0200428{
Michal Vaskofeca4fb2020-10-05 08:58:40 +0200429 ly_bool incomplete;
430
431 LY_CHECK_RET(lyd_create_meta(parent, meta, mod, name, name_len, value, value_len, dynamic, format, prefix_data,
432 hints, &incomplete));
433
434 if (incomplete && !(lydctx->parse_options & LYD_PARSE_ONLY)) {
Radek Krejci3d92e442020-10-12 12:48:13 +0200435 LY_CHECK_RET(ly_set_add(&lydctx->unres_meta_type, *meta, 1, NULL));
Radek Krejci1798aae2020-07-14 13:26:06 +0200436 }
Michal Vaskofeca4fb2020-10-05 08:58:40 +0200437 return LY_SUCCESS;
Radek Krejci1798aae2020-07-14 13:26:06 +0200438}