blob: a7f120097500fbd94f48e3e43475ed0025139e21 [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"
28#include "dict.h"
29#include "log.h"
Radek Krejcif0e1ba52020-05-22 15:14:35 +020030#include "parser_internal.h"
Radek Krejcica376bd2020-06-11 16:04:06 +020031#include "tree_schema_internal.h"
Radek Krejcif0e1ba52020-05-22 15:14:35 +020032
33API LY_IN_TYPE
34ly_in_type(const struct ly_in *in)
35{
36 LY_CHECK_ARG_RET(NULL, in, LY_IN_ERROR);
37 return in->type;
38}
39
40API LY_ERR
41ly_in_new_fd(int fd, struct ly_in **in)
42{
43 size_t length;
44 char *addr;
45
46 LY_CHECK_ARG_RET(NULL, fd >= 0, in, LY_EINVAL);
47
48 LY_CHECK_RET(ly_mmap(NULL, fd, &length, (void **)&addr));
49 if (!addr) {
50 LOGERR(NULL, LY_EINVAL, "Empty input file.");
51 return LY_EINVAL;
52 }
53
54 *in = calloc(1, sizeof **in);
55 LY_CHECK_ERR_RET(!*in, LOGMEM(NULL); ly_munmap(addr, length), LY_EMEM);
56
57 (*in)->type = LY_IN_FD;
58 (*in)->method.fd = fd;
59 (*in)->current = (*in)->start = addr;
60 (*in)->length = length;
61
62 return LY_SUCCESS;
63}
64
65API int
66ly_in_fd(struct ly_in *in, int fd)
67{
68 int prev_fd;
69 size_t length;
70 const char *addr;
71
72 LY_CHECK_ARG_RET(NULL, in, in->type == LY_IN_FD, -1);
73
74 prev_fd = in->method.fd;
75
76 if (fd != -1) {
77 LY_CHECK_RET(ly_mmap(NULL, fd, &length, (void **)&addr), -1);
78 if (!addr) {
79 LOGERR(NULL, LY_EINVAL, "Empty input file.");
80 return -1;
81 }
82
83 ly_munmap((char*)in->start, in->length);
84
85 in->method.fd = fd;
86 in->current = in->start = addr;
87 in->length = length;
88 }
89
90 return prev_fd;
91}
92
93API LY_ERR
94ly_in_new_file(FILE *f, struct ly_in **in)
95{
96 LY_CHECK_ARG_RET(NULL, f, in, LY_EINVAL);
97
98 LY_CHECK_RET(ly_in_new_fd(fileno(f), in));
99
100 /* convert the LY_IN_FD input handler into the LY_IN_FILE */
101 (*in)->type = LY_IN_FILE;
102 (*in)->method.f = f;
103
104 return LY_SUCCESS;
105}
106
107API FILE *
108ly_in_file(struct ly_in *in, FILE *f)
109{
110 FILE *prev_f;
111
112 LY_CHECK_ARG_RET(NULL, in, in->type == LY_IN_FILE, NULL);
113
114 prev_f = in->method.f;
115
116 if (f) {
117 /* convert LY_IN_FILE handler into LY_IN_FD to be able to update it via ly_in_fd() */
118 in->type = LY_IN_FD;
119 in->method.fd = fileno(prev_f);
120 if (ly_in_fd(in, fileno(f)) == -1) {
121 in->type = LY_IN_FILE;
122 in->method.f = prev_f;
123 return NULL;
124 }
125
126 /* if success, convert the result back */
127 in->type = LY_IN_FILE;
128 in->method.f = f;
129 }
130
131 return prev_f;
132}
133
134API LY_ERR
135ly_in_new_memory(const char *str, struct ly_in **in)
136{
137 LY_CHECK_ARG_RET(NULL, str, in, LY_EINVAL);
138
139 *in = calloc(1, sizeof **in);
140 LY_CHECK_ERR_RET(!*in, LOGMEM(NULL), LY_EMEM);
141
142 (*in)->type = LY_IN_MEMORY;
143 (*in)->start = (*in)->current = str;
144
145 return LY_SUCCESS;
146}
147
148const char *
149ly_in_memory(struct ly_in *in, const char *str)
150{
151 const char *data;
152
153 LY_CHECK_ARG_RET(NULL, in, in->type == LY_IN_MEMORY, NULL);
154
155 data = in->current;
156
157 if (str) {
158 in->start = in->current = str;
159 }
160
161 return data;
162}
163
164API LY_ERR
165ly_in_reset(struct ly_in *in)
166{
167 LY_CHECK_ARG_RET(NULL, in, LY_EINVAL);
168
169 in->current = in->start;
170 return LY_SUCCESS;
171}
172
173API LY_ERR
174ly_in_new_filepath(const char *filepath, size_t len, struct ly_in **in)
175{
176 LY_ERR ret;
177 char *fp;
178 int fd;
179
180 LY_CHECK_ARG_RET(NULL, filepath, in, LY_EINVAL);
181
182 if (len) {
183 fp = strndup(filepath, len);
184 } else {
185 fp = strdup(filepath);
186 }
187
188 fd = open(fp, O_RDONLY);
189 LY_CHECK_ERR_RET(!fd, LOGERR(NULL, LY_ESYS, "Failed to open file \"%s\" (%s).", fp, strerror(errno)); free(fp), LY_ESYS);
190
191 LY_CHECK_ERR_RET(ret = ly_in_new_fd(fd, in), free(fp), ret);
192
193 /* convert the LY_IN_FD input handler into the LY_IN_FILE */
194 (*in)->type = LY_IN_FILEPATH;
195 (*in)->method.fpath.fd = fd;
196 (*in)->method.fpath.filepath = fp;
197
198 return LY_SUCCESS;
199}
200
201API const char *
202ly_in_filepath(struct ly_in *in, const char *filepath, size_t len)
203{
204 int fd, prev_fd;
205 char *fp = NULL;
206
207 LY_CHECK_ARG_RET(NULL, in, in->type == LY_IN_FILEPATH, filepath ? NULL : ((void *)-1));
208
209 if (!filepath) {
210 return in->method.fpath.filepath;
211 }
212
213 if (len) {
214 fp = strndup(filepath, len);
215 } else {
216 fp = strdup(filepath);
217 }
218
219 /* replace filepath */
220 fd = open(fp, O_RDONLY);
221 LY_CHECK_ERR_RET(!fd, LOGERR(NULL, LY_ESYS, "Failed to open file \"%s\" (%s).", fp, strerror(errno)); free(fp), NULL);
222
223 /* convert LY_IN_FILEPATH handler into LY_IN_FD to be able to update it via ly_in_fd() */
224 in->type = LY_IN_FD;
225 prev_fd = ly_in_fd(in, fd);
226 LY_CHECK_ERR_RET(prev_fd == -1, in->type = LY_IN_FILEPATH; free(fp), NULL);
227
228 /* and convert the result back */
229 in->type = LY_IN_FILEPATH;
230 close(prev_fd);
231 free(in->method.fpath.filepath);
232 in->method.fpath.fd = fd;
233 in->method.fpath.filepath = fp;
234
235 return NULL;
236}
237
238void
239lys_parser_fill_filepath(struct ly_ctx *ctx, struct ly_in *in, const char **filepath)
240{
241 char path[PATH_MAX];
242 char proc_path[32];
243 int len;
244
245 LY_CHECK_ARG_RET(NULL, ctx, in, filepath, );
246 if (*filepath) {
247 /* filepath already set */
248 return;
249 }
250
251 switch (in->type) {
252 case LY_IN_FILEPATH:
253 if (realpath(in->method.fpath.filepath, path) != NULL) {
254 *filepath = lydict_insert(ctx, path, 0);
255 } else {
256 *filepath = lydict_insert(ctx, in->method.fpath.filepath, 0);
257 }
258
259 break;
260 case LY_IN_FD:
261#ifdef __APPLE__
262 if (fcntl(in->method.fd, F_GETPATH, path) != -1) {
263 *filepath = lydict_insert(ctx, path, 0);
264 }
265#else
266 /* get URI if there is /proc */
267 sprintf(proc_path, "/proc/self/fd/%d", in->method.fd);
268 if ((len = readlink(proc_path, path, PATH_MAX - 1)) > 0) {
269 *filepath = lydict_insert(ctx, path, len);
270 }
271#endif
272 break;
273 case LY_IN_MEMORY:
274 case LY_IN_FILE:
275 /* nothing to do */
276 break;
277 default:
278 LOGINT(ctx);
279 break;
280 }
281
282}
283
284API void
285ly_in_free(struct ly_in *in, int destroy)
286{
287 if (!in) {
288 return;
289 } else if (in->type == LY_IN_ERROR) {
290 LOGINT(NULL);
291 return;
292 }
293
294 if (destroy) {
295 if (in->type == LY_IN_MEMORY) {
296 free((char*)in->start);
297 } else {
298 ly_munmap((char*)in->start, in->length);
299
300 if (in->type == LY_IN_FILE) {
301 fclose(in->method.f);
302 } else {
303 close(in->method.fd);
304
305 if (in->type == LY_IN_FILEPATH) {
306 free(in->method.fpath.filepath);
307 }
308 }
309 }
310 } else if (in->type != LY_IN_MEMORY) {
311 ly_munmap((char*)in->start, in->length);
312
313 if (in->type == LY_IN_FILEPATH) {
314 close(in->method.fpath.fd);
315 free(in->method.fpath.filepath);
316 }
317 }
318
319 free(in);
320}