blob: fe8528bfd3eb5b0e49946be8a1ffbf5f3c6b1a48 [file] [log] [blame]
Radek Krejcif0e1ba52020-05-22 15:14:35 +02001/**
2 * @file printer.c
3 * @author Radek Krejci <rkrejci@cesnet.cz>
4 * @brief Generic libyang printers functions.
5 *
6 * Copyright (c) 2015 - 2019 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 */
14
15#define _GNU_SOURCE
16
Radek Krejcica376bd2020-06-11 16:04:06 +020017#include "parser.h"
18
Radek Krejcif0e1ba52020-05-22 15:14:35 +020019#include <errno.h>
20#include <fcntl.h>
21#include <limits.h>
22#include <stdio.h>
Radek Krejcica376bd2020-06-11 16:04:06 +020023#include <stdlib.h>
Radek Krejcif0e1ba52020-05-22 15:14:35 +020024#include <string.h>
Radek Krejcica376bd2020-06-11 16:04:06 +020025#include <unistd.h>
Radek Krejcif0e1ba52020-05-22 15:14:35 +020026
Radek Krejcica376bd2020-06-11 16:04:06 +020027#include "common.h"
Michal Vasko5aa44c02020-06-29 11:47:02 +020028#include "compat.h"
Radek Krejcica376bd2020-06-11 16:04:06 +020029#include "dict.h"
30#include "log.h"
Radek Krejcif0e1ba52020-05-22 15:14:35 +020031#include "parser_internal.h"
Radek Krejcica376bd2020-06-11 16:04:06 +020032#include "tree_schema_internal.h"
Radek Krejcif0e1ba52020-05-22 15:14:35 +020033
34API LY_IN_TYPE
35ly_in_type(const struct ly_in *in)
36{
37 LY_CHECK_ARG_RET(NULL, in, LY_IN_ERROR);
38 return in->type;
39}
40
41API LY_ERR
42ly_in_new_fd(int fd, struct ly_in **in)
43{
44 size_t length;
45 char *addr;
46
47 LY_CHECK_ARG_RET(NULL, fd >= 0, in, LY_EINVAL);
48
49 LY_CHECK_RET(ly_mmap(NULL, fd, &length, (void **)&addr));
50 if (!addr) {
51 LOGERR(NULL, LY_EINVAL, "Empty input file.");
52 return LY_EINVAL;
53 }
54
55 *in = calloc(1, sizeof **in);
56 LY_CHECK_ERR_RET(!*in, LOGMEM(NULL); ly_munmap(addr, length), LY_EMEM);
57
58 (*in)->type = LY_IN_FD;
59 (*in)->method.fd = fd;
Michal Vasko63f3d842020-07-08 10:10:14 +020060 (*in)->current = (*in)->start = (*in)->func_start = addr;
Radek Krejcif0e1ba52020-05-22 15:14:35 +020061 (*in)->length = length;
62
63 return LY_SUCCESS;
64}
65
66API int
67ly_in_fd(struct ly_in *in, int fd)
68{
69 int prev_fd;
70 size_t length;
71 const char *addr;
72
73 LY_CHECK_ARG_RET(NULL, in, in->type == LY_IN_FD, -1);
74
75 prev_fd = in->method.fd;
76
77 if (fd != -1) {
78 LY_CHECK_RET(ly_mmap(NULL, fd, &length, (void **)&addr), -1);
79 if (!addr) {
80 LOGERR(NULL, LY_EINVAL, "Empty input file.");
81 return -1;
82 }
83
84 ly_munmap((char*)in->start, in->length);
85
86 in->method.fd = fd;
87 in->current = in->start = addr;
88 in->length = length;
89 }
90
91 return prev_fd;
92}
93
94API LY_ERR
95ly_in_new_file(FILE *f, struct ly_in **in)
96{
97 LY_CHECK_ARG_RET(NULL, f, in, LY_EINVAL);
98
99 LY_CHECK_RET(ly_in_new_fd(fileno(f), in));
100
101 /* convert the LY_IN_FD input handler into the LY_IN_FILE */
102 (*in)->type = LY_IN_FILE;
103 (*in)->method.f = f;
104
105 return LY_SUCCESS;
106}
107
108API FILE *
109ly_in_file(struct ly_in *in, FILE *f)
110{
111 FILE *prev_f;
112
113 LY_CHECK_ARG_RET(NULL, in, in->type == LY_IN_FILE, NULL);
114
115 prev_f = in->method.f;
116
117 if (f) {
118 /* convert LY_IN_FILE handler into LY_IN_FD to be able to update it via ly_in_fd() */
119 in->type = LY_IN_FD;
120 in->method.fd = fileno(prev_f);
121 if (ly_in_fd(in, fileno(f)) == -1) {
122 in->type = LY_IN_FILE;
123 in->method.f = prev_f;
124 return NULL;
125 }
126
127 /* if success, convert the result back */
128 in->type = LY_IN_FILE;
129 in->method.f = f;
130 }
131
132 return prev_f;
133}
134
135API LY_ERR
136ly_in_new_memory(const char *str, struct ly_in **in)
137{
138 LY_CHECK_ARG_RET(NULL, str, in, LY_EINVAL);
139
140 *in = calloc(1, sizeof **in);
141 LY_CHECK_ERR_RET(!*in, LOGMEM(NULL), LY_EMEM);
142
143 (*in)->type = LY_IN_MEMORY;
Michal Vasko63f3d842020-07-08 10:10:14 +0200144 (*in)->start = (*in)->current = (*in)->func_start = str;
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200145
146 return LY_SUCCESS;
147}
148
Michal Vasko63f3d842020-07-08 10:10:14 +0200149API const char *
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200150ly_in_memory(struct ly_in *in, const char *str)
151{
152 const char *data;
153
154 LY_CHECK_ARG_RET(NULL, in, in->type == LY_IN_MEMORY, NULL);
155
156 data = in->current;
157
158 if (str) {
159 in->start = in->current = str;
160 }
161
162 return data;
163}
164
165API LY_ERR
166ly_in_reset(struct ly_in *in)
167{
168 LY_CHECK_ARG_RET(NULL, in, LY_EINVAL);
169
Michal Vasko63f3d842020-07-08 10:10:14 +0200170 in->current = in->func_start = in->start;
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200171 return LY_SUCCESS;
172}
173
174API LY_ERR
175ly_in_new_filepath(const char *filepath, size_t len, struct ly_in **in)
176{
177 LY_ERR ret;
178 char *fp;
179 int fd;
180
181 LY_CHECK_ARG_RET(NULL, filepath, in, LY_EINVAL);
182
183 if (len) {
184 fp = strndup(filepath, len);
185 } else {
186 fp = strdup(filepath);
187 }
188
189 fd = open(fp, O_RDONLY);
Michal Vaskof2eb8af2020-07-14 12:22:40 +0200190 LY_CHECK_ERR_RET(fd == -1, LOGERR(NULL, LY_ESYS, "Failed to open file \"%s\" (%s).", fp, strerror(errno)); free(fp),
191 LY_ESYS);
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200192
193 LY_CHECK_ERR_RET(ret = ly_in_new_fd(fd, in), free(fp), ret);
194
195 /* convert the LY_IN_FD input handler into the LY_IN_FILE */
196 (*in)->type = LY_IN_FILEPATH;
197 (*in)->method.fpath.fd = fd;
198 (*in)->method.fpath.filepath = fp;
199
200 return LY_SUCCESS;
201}
202
203API const char *
204ly_in_filepath(struct ly_in *in, const char *filepath, size_t len)
205{
206 int fd, prev_fd;
207 char *fp = NULL;
208
209 LY_CHECK_ARG_RET(NULL, in, in->type == LY_IN_FILEPATH, filepath ? NULL : ((void *)-1));
210
211 if (!filepath) {
212 return in->method.fpath.filepath;
213 }
214
215 if (len) {
216 fp = strndup(filepath, len);
217 } else {
218 fp = strdup(filepath);
219 }
220
221 /* replace filepath */
222 fd = open(fp, O_RDONLY);
223 LY_CHECK_ERR_RET(!fd, LOGERR(NULL, LY_ESYS, "Failed to open file \"%s\" (%s).", fp, strerror(errno)); free(fp), NULL);
224
225 /* convert LY_IN_FILEPATH handler into LY_IN_FD to be able to update it via ly_in_fd() */
226 in->type = LY_IN_FD;
227 prev_fd = ly_in_fd(in, fd);
228 LY_CHECK_ERR_RET(prev_fd == -1, in->type = LY_IN_FILEPATH; free(fp), NULL);
229
230 /* and convert the result back */
231 in->type = LY_IN_FILEPATH;
232 close(prev_fd);
233 free(in->method.fpath.filepath);
234 in->method.fpath.fd = fd;
235 in->method.fpath.filepath = fp;
236
237 return NULL;
238}
239
240void
241lys_parser_fill_filepath(struct ly_ctx *ctx, struct ly_in *in, const char **filepath)
242{
243 char path[PATH_MAX];
Michal Vasko5aa44c02020-06-29 11:47:02 +0200244#ifndef __APPLE__
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200245 char proc_path[32];
246 int len;
Michal Vasko5aa44c02020-06-29 11:47:02 +0200247#endif
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200248
249 LY_CHECK_ARG_RET(NULL, ctx, in, filepath, );
250 if (*filepath) {
251 /* filepath already set */
252 return;
253 }
254
255 switch (in->type) {
256 case LY_IN_FILEPATH:
257 if (realpath(in->method.fpath.filepath, path) != NULL) {
258 *filepath = lydict_insert(ctx, path, 0);
259 } else {
260 *filepath = lydict_insert(ctx, in->method.fpath.filepath, 0);
261 }
262
263 break;
264 case LY_IN_FD:
265#ifdef __APPLE__
266 if (fcntl(in->method.fd, F_GETPATH, path) != -1) {
267 *filepath = lydict_insert(ctx, path, 0);
268 }
269#else
270 /* get URI if there is /proc */
271 sprintf(proc_path, "/proc/self/fd/%d", in->method.fd);
272 if ((len = readlink(proc_path, path, PATH_MAX - 1)) > 0) {
273 *filepath = lydict_insert(ctx, path, len);
274 }
275#endif
276 break;
277 case LY_IN_MEMORY:
278 case LY_IN_FILE:
279 /* nothing to do */
280 break;
281 default:
282 LOGINT(ctx);
283 break;
284 }
285
286}
287
288API void
289ly_in_free(struct ly_in *in, int destroy)
290{
291 if (!in) {
292 return;
293 } else if (in->type == LY_IN_ERROR) {
294 LOGINT(NULL);
295 return;
296 }
297
298 if (destroy) {
299 if (in->type == LY_IN_MEMORY) {
300 free((char*)in->start);
301 } else {
302 ly_munmap((char*)in->start, in->length);
303
304 if (in->type == LY_IN_FILE) {
305 fclose(in->method.f);
306 } else {
307 close(in->method.fd);
308
309 if (in->type == LY_IN_FILEPATH) {
310 free(in->method.fpath.filepath);
311 }
312 }
313 }
314 } else if (in->type != LY_IN_MEMORY) {
315 ly_munmap((char*)in->start, in->length);
316
317 if (in->type == LY_IN_FILEPATH) {
318 close(in->method.fpath.fd);
319 free(in->method.fpath.filepath);
320 }
321 }
322
323 free(in);
324}
Michal Vasko63f3d842020-07-08 10:10:14 +0200325
326LY_ERR
327ly_in_read(struct ly_in *in, void *buf, size_t count)
328{
329 if (in->length && (in->length - (in->current - in->start) < count)) {
330 /* EOF */
331 return LY_EDENIED;
332 }
333
334 memcpy(buf, in->current, count);
335 in->current += count;
336 return LY_SUCCESS;
337}
338
339API size_t
340ly_in_parsed(const struct ly_in *in)
341{
342 return in->current - in->func_start;
343}
344
345LY_ERR
346ly_in_skip(struct ly_in *in, size_t count)
347{
348 if (in->length && (in->length - (in->current - in->start) < count)) {
349 /* EOF */
350 return LY_EDENIED;
351 }
352
353 in->current += count;
354 return LY_SUCCESS;
355}