blob: a394f0df0f2a4801377aec1bf6ea7828bf4c77f1 [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;
60 (*in)->current = (*in)->start = addr;
61 (*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;
144 (*in)->start = (*in)->current = str;
145
146 return LY_SUCCESS;
147}
148
149const char *
150ly_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
170 in->current = in->start;
171 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);
190 LY_CHECK_ERR_RET(!fd, LOGERR(NULL, LY_ESYS, "Failed to open file \"%s\" (%s).", fp, strerror(errno)); free(fp), LY_ESYS);
191
192 LY_CHECK_ERR_RET(ret = ly_in_new_fd(fd, in), free(fp), ret);
193
194 /* convert the LY_IN_FD input handler into the LY_IN_FILE */
195 (*in)->type = LY_IN_FILEPATH;
196 (*in)->method.fpath.fd = fd;
197 (*in)->method.fpath.filepath = fp;
198
199 return LY_SUCCESS;
200}
201
202API const char *
203ly_in_filepath(struct ly_in *in, const char *filepath, size_t len)
204{
205 int fd, prev_fd;
206 char *fp = NULL;
207
208 LY_CHECK_ARG_RET(NULL, in, in->type == LY_IN_FILEPATH, filepath ? NULL : ((void *)-1));
209
210 if (!filepath) {
211 return in->method.fpath.filepath;
212 }
213
214 if (len) {
215 fp = strndup(filepath, len);
216 } else {
217 fp = strdup(filepath);
218 }
219
220 /* replace filepath */
221 fd = open(fp, O_RDONLY);
222 LY_CHECK_ERR_RET(!fd, LOGERR(NULL, LY_ESYS, "Failed to open file \"%s\" (%s).", fp, strerror(errno)); free(fp), NULL);
223
224 /* convert LY_IN_FILEPATH handler into LY_IN_FD to be able to update it via ly_in_fd() */
225 in->type = LY_IN_FD;
226 prev_fd = ly_in_fd(in, fd);
227 LY_CHECK_ERR_RET(prev_fd == -1, in->type = LY_IN_FILEPATH; free(fp), NULL);
228
229 /* and convert the result back */
230 in->type = LY_IN_FILEPATH;
231 close(prev_fd);
232 free(in->method.fpath.filepath);
233 in->method.fpath.fd = fd;
234 in->method.fpath.filepath = fp;
235
236 return NULL;
237}
238
239void
240lys_parser_fill_filepath(struct ly_ctx *ctx, struct ly_in *in, const char **filepath)
241{
242 char path[PATH_MAX];
Michal Vasko5aa44c02020-06-29 11:47:02 +0200243#ifndef __APPLE__
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200244 char proc_path[32];
245 int len;
Michal Vasko5aa44c02020-06-29 11:47:02 +0200246#endif
Radek Krejcif0e1ba52020-05-22 15:14:35 +0200247
248 LY_CHECK_ARG_RET(NULL, ctx, in, filepath, );
249 if (*filepath) {
250 /* filepath already set */
251 return;
252 }
253
254 switch (in->type) {
255 case LY_IN_FILEPATH:
256 if (realpath(in->method.fpath.filepath, path) != NULL) {
257 *filepath = lydict_insert(ctx, path, 0);
258 } else {
259 *filepath = lydict_insert(ctx, in->method.fpath.filepath, 0);
260 }
261
262 break;
263 case LY_IN_FD:
264#ifdef __APPLE__
265 if (fcntl(in->method.fd, F_GETPATH, path) != -1) {
266 *filepath = lydict_insert(ctx, path, 0);
267 }
268#else
269 /* get URI if there is /proc */
270 sprintf(proc_path, "/proc/self/fd/%d", in->method.fd);
271 if ((len = readlink(proc_path, path, PATH_MAX - 1)) > 0) {
272 *filepath = lydict_insert(ctx, path, len);
273 }
274#endif
275 break;
276 case LY_IN_MEMORY:
277 case LY_IN_FILE:
278 /* nothing to do */
279 break;
280 default:
281 LOGINT(ctx);
282 break;
283 }
284
285}
286
287API void
288ly_in_free(struct ly_in *in, int destroy)
289{
290 if (!in) {
291 return;
292 } else if (in->type == LY_IN_ERROR) {
293 LOGINT(NULL);
294 return;
295 }
296
297 if (destroy) {
298 if (in->type == LY_IN_MEMORY) {
299 free((char*)in->start);
300 } else {
301 ly_munmap((char*)in->start, in->length);
302
303 if (in->type == LY_IN_FILE) {
304 fclose(in->method.f);
305 } else {
306 close(in->method.fd);
307
308 if (in->type == LY_IN_FILEPATH) {
309 free(in->method.fpath.filepath);
310 }
311 }
312 }
313 } else if (in->type != LY_IN_MEMORY) {
314 ly_munmap((char*)in->start, in->length);
315
316 if (in->type == LY_IN_FILEPATH) {
317 close(in->method.fpath.fd);
318 free(in->method.fpath.filepath);
319 }
320 }
321
322 free(in);
323}