blob: e34d42eb52b5b0585378790a14058391b358ebe2 [file] [log] [blame]
Michal Vasko1324b6c2018-09-07 11:16:23 +02001/**
2 * @file common.c
3 * @author Michal Vasko <mvasko@cesnet.cz>
4 * @brief common internal definitions for libyang
5 *
6 * Copyright (c) 2018 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 */
Radek Krejcib7db73a2018-10-24 14:18:40 +020014
15#include "common.h"
Michal Vasko1324b6c2018-09-07 11:16:23 +020016
Radek Krejci86d106e2018-10-18 09:53:19 +020017#include <assert.h>
18#include <errno.h>
Michal Vasko1324b6c2018-09-07 11:16:23 +020019#include <stdlib.h>
Michal Vasko841d1a92018-09-07 15:40:31 +020020#include <ctype.h>
21#include <string.h>
Radek Krejci86d106e2018-10-18 09:53:19 +020022#include <sys/mman.h>
23#include <sys/stat.h>
Radek Krejci86d106e2018-10-18 09:53:19 +020024#include <unistd.h>
Michal Vasko841d1a92018-09-07 15:40:31 +020025
Radek Krejcie7b95092019-05-15 11:03:07 +020026#include "extensions.h"
Michal Vasko841d1a92018-09-07 15:40:31 +020027#include "tree_schema.h"
Michal Vasko1324b6c2018-09-07 11:16:23 +020028
Radek Krejcic59bc972018-09-17 16:13:06 +020029const char *const ly_stmt_list[] = {
30 [YANG_ACTION] = "action",
31 [YANG_ANYDATA] = "anydata",
32 [YANG_ANYXML] = "anyxml",
33 [YANG_ARGUMENT] = "argument",
34 [YANG_AUGMENT] = "augment",
35 [YANG_BASE] = "base",
36 [YANG_BELONGS_TO] = "belongs-to",
37 [YANG_BIT] = "bit",
38 [YANG_CASE] = "case",
39 [YANG_CHOICE] = "choice",
40 [YANG_CONFIG] = "config",
41 [YANG_CONTACT] = "contact",
42 [YANG_CONTAINER] = "container",
43 [YANG_CUSTOM] = "<extension-instance>",
44 [YANG_DEFAULT] = "default",
45 [YANG_DESCRIPTION] = "description",
46 [YANG_DEVIATE] = "deviate",
47 [YANG_DEVIATION] = "deviation",
48 [YANG_ENUM] = "enum",
49 [YANG_ERROR_APP_TAG] = "error-app-tag",
50 [YANG_ERROR_MESSAGE] = "error-message",
51 [YANG_EXTENSION] = "extension",
52 [YANG_FEATURE] = "feature",
53 [YANG_FRACTION_DIGITS] = "fraction-digits",
54 [YANG_GROUPING] = "grouping",
55 [YANG_IDENTITY] = "identitiy",
56 [YANG_IF_FEATURE] = "if-feature",
57 [YANG_IMPORT] = "import",
58 [YANG_INCLUDE] = "include",
59 [YANG_INPUT] = "input",
60 [YANG_KEY] = "key",
61 [YANG_LEAF] = "leaf",
62 [YANG_LEAF_LIST] = "leaf-list",
63 [YANG_LENGTH] = "length",
64 [YANG_LIST] = "list",
65 [YANG_MANDATORY] = "mandatory",
66 [YANG_MAX_ELEMENTS] = "max-elements",
67 [YANG_MIN_ELEMENTS] = "min-elements",
68 [YANG_MODIFIER] = "modifier",
69 [YANG_MODULE] = "module",
70 [YANG_MUST] = "must",
71 [YANG_NAMESPACE] = "namespace",
72 [YANG_NOTIFICATION] = "notification",
73 [YANG_ORDERED_BY] = "ordered-by",
74 [YANG_ORGANIZATION] = "organization",
75 [YANG_OUTPUT] = "output",
76 [YANG_PATH] = "path",
77 [YANG_PATTERN] = "pattern",
78 [YANG_POSITION] = "position",
79 [YANG_PREFIX] = "prefix",
80 [YANG_PRESENCE] = "presence",
81 [YANG_RANGE] = "range",
82 [YANG_REFERENCE] = "reference",
83 [YANG_REFINE] = "refine",
84 [YANG_REQUIRE_INSTANCE] = "require-instance",
85 [YANG_REVISION] = "revision",
86 [YANG_REVISION_DATE] = "revision-date",
87 [YANG_RPC] = "rpc",
88 [YANG_STATUS] = "status",
89 [YANG_SUBMODULE] = "submodule",
90 [YANG_TYPE] = "type",
91 [YANG_TYPEDEF] = "typedef",
92 [YANG_UNIQUE] = "unique",
93 [YANG_UNITS] = "units",
94 [YANG_USES] = "uses",
95 [YANG_VALUE] = "value",
96 [YANG_WHEN] = "when",
97 [YANG_YANG_VERSION] = "yang-version",
98 [YANG_YIN_ELEMENT] = "yin-element",
99 [YANG_SEMICOLON] = ";",
100 [YANG_LEFT_BRACE] = "{",
101 [YANG_RIGHT_BRACE] = "}",
102};
103
104const char *const lyext_substmt_list[] = {
105 [LYEXT_SUBSTMT_ARGUMENT] = "argument",
106 [LYEXT_SUBSTMT_BASE] = "base",
107 [LYEXT_SUBSTMT_BELONGSTO] = "belongs-to",
108 [LYEXT_SUBSTMT_CONTACT] = "contact",
109 [LYEXT_SUBSTMT_DEFAULT] = "default",
110 [LYEXT_SUBSTMT_DESCRIPTION] = "description",
111 [LYEXT_SUBSTMT_ERRTAG] = "error-app-tag",
112 [LYEXT_SUBSTMT_ERRMSG] = "error-message",
113 [LYEXT_SUBSTMT_KEY] = "key",
114 [LYEXT_SUBSTMT_NAMESPACE] = "namespace",
115 [LYEXT_SUBSTMT_ORGANIZATION] = "organization",
116 [LYEXT_SUBSTMT_PATH] = "path",
117 [LYEXT_SUBSTMT_PREFIX] = "prefix",
118 [LYEXT_SUBSTMT_PRESENCE] = "presence",
119 [LYEXT_SUBSTMT_REFERENCE] = "reference",
120 [LYEXT_SUBSTMT_REVISIONDATE] = "revision-date",
121 [LYEXT_SUBSTMT_UNITS] = "units",
122 [LYEXT_SUBSTMT_VALUE] = "value",
123 [LYEXT_SUBSTMT_VERSION] = "yang-version",
124 [LYEXT_SUBSTMT_MODIFIER] = "modifier",
125 [LYEXT_SUBSTMT_REQINSTANCE] = "require-instance",
126 [LYEXT_SUBSTMT_YINELEM] = "yin-element",
127 [LYEXT_SUBSTMT_CONFIG] = "config",
128 [LYEXT_SUBSTMT_MANDATORY] = "mandatory",
129 [LYEXT_SUBSTMT_ORDEREDBY] = "ordered-by",
130 [LYEXT_SUBSTMT_STATUS] = "status",
131 [LYEXT_SUBSTMT_FRACDIGITS] = "fraction-digits",
132 [LYEXT_SUBSTMT_MAX] = "max-elements",
133 [LYEXT_SUBSTMT_MIN] = "min-elements",
134 [LYEXT_SUBSTMT_POSITION] = "position",
135 [LYEXT_SUBSTMT_UNIQUE] = "unique",
136 [LYEXT_SUBSTMT_IFFEATURE] = "if-feature",
137};
138
139const char *const ly_devmod_list[] = {
140 [LYS_DEV_NOT_SUPPORTED] = "not-supported",
141 [LYS_DEV_ADD] = "add",
142 [LYS_DEV_DELETE] = "delete",
143 [LYS_DEV_REPLACE] = "replace",
144};
145
Michal Vasko1324b6c2018-09-07 11:16:23 +0200146void *
147ly_realloc(void *ptr, size_t size)
148{
149 void *new_mem;
150
151 new_mem = realloc(ptr, size);
152 if (!new_mem) {
153 free(ptr);
154 }
155
156 return new_mem;
157}
Michal Vasko841d1a92018-09-07 15:40:31 +0200158
Radek Krejcib416be62018-10-01 14:51:45 +0200159LY_ERR
160ly_getutf8(const char **input, unsigned int *utf8_char, size_t *bytes_read)
161{
162 unsigned int c, len;
163 int aux;
164 int i;
165
Radek Krejcicc6a45c2019-05-13 10:16:14 +0200166 if (bytes_read) {
167 (*bytes_read) = 0;
168 }
169
Radek Krejcib416be62018-10-01 14:51:45 +0200170 c = (*input)[0];
171 LY_CHECK_RET(!c, LY_EINVAL);
172
173 if (!(c & 0x80)) {
174 /* one byte character */
175 len = 1;
176
177 if (c < 0x20 && c != 0x9 && c != 0xa && c != 0xd) {
178 return LY_EINVAL;
179 }
180 } else if ((c & 0xe0) == 0xc0) {
181 /* two bytes character */
182 len = 2;
183
184 aux = (*input)[1];
185 if ((aux & 0xc0) != 0x80) {
186 return LY_EINVAL;
187 }
188 c = ((c & 0x1f) << 6) | (aux & 0x3f);
189
190 if (c < 0x80) {
191 return LY_EINVAL;
192 }
193 } else if ((c & 0xf0) == 0xe0) {
194 /* three bytes character */
195 len = 3;
196
197 c &= 0x0f;
198 for (i = 1; i <= 2; i++) {
199 aux = (*input)[i];
200 if ((aux & 0xc0) != 0x80) {
201 return LY_EINVAL;
202 }
203
204 c = (c << 6) | (aux & 0x3f);
205 }
206
207 if (c < 0x800 || (c > 0xd7ff && c < 0xe000) || c > 0xfffd) {
208 return LY_EINVAL;
209 }
210 } else if ((c & 0xf8) == 0xf0) {
211 /* four bytes character */
212 len = 4;
213
214 c &= 0x07;
215 for (i = 1; i <= 3; i++) {
216 aux = (*input)[i];
217 if ((aux & 0xc0) != 0x80) {
218 return LY_EINVAL;
219 }
220
221 c = (c << 6) | (aux & 0x3f);
222 }
223
224 if (c < 0x1000 || c > 0x10ffff) {
225 return LY_EINVAL;
226 }
227 } else {
228 return LY_EINVAL;
229 }
230
231 (*utf8_char) = c;
232 (*input) += len;
233 if (bytes_read) {
234 (*bytes_read) = len;
235 }
236 return LY_SUCCESS;
237}
238
Radek Krejcid972c252018-09-25 13:23:39 +0200239size_t
240LY_VCODE_INSTREXP_len(const char *str)
241{
242 size_t len = 0;
243 if (!str) {
244 return len;
245 } else if (!str[0]) {
246 return 1;
247 }
248 for (len = 1; len < LY_VCODE_INSTREXP_MAXLEN && str[len]; ++len);
249 return len;
250}
251
Radek Krejcif345c012018-09-19 11:12:59 +0200252LY_ERR
Radek Krejci86d106e2018-10-18 09:53:19 +0200253ly_mmap(struct ly_ctx *ctx, int fd, size_t *length, void **addr)
Michal Vasko841d1a92018-09-07 15:40:31 +0200254{
Radek Krejci86d106e2018-10-18 09:53:19 +0200255 struct stat sb;
256 long pagesize;
257 size_t m;
Michal Vasko841d1a92018-09-07 15:40:31 +0200258
Radek Krejci86d106e2018-10-18 09:53:19 +0200259 assert(length);
260 assert(addr);
261 assert(fd >= 0);
Michal Vasko841d1a92018-09-07 15:40:31 +0200262
Radek Krejci86d106e2018-10-18 09:53:19 +0200263 if (fstat(fd, &sb) == -1) {
264 LOGERR(ctx, LY_ESYS, "Failed to stat the file descriptor (%s) for the mmap().", strerror(errno));
265 return LY_ESYS;
Michal Vasko841d1a92018-09-07 15:40:31 +0200266 }
Radek Krejci86d106e2018-10-18 09:53:19 +0200267 if (!S_ISREG(sb.st_mode)) {
268 LOGERR(ctx, LY_EINVAL, "File to mmap() is not a regular file.");
269 return LY_ESYS;
Michal Vasko841d1a92018-09-07 15:40:31 +0200270 }
Radek Krejci86d106e2018-10-18 09:53:19 +0200271 if (!sb.st_size) {
272 *addr = NULL;
273 return LY_SUCCESS;
274 }
275 pagesize = sysconf(_SC_PAGESIZE);
276
277 m = sb.st_size % pagesize;
278 if (m && pagesize - m >= 1) {
279 /* there will be enough space (at least 1 byte) after the file content mapping to provide zeroed NULL-termination byte */
280 *length = sb.st_size + 1;
281 *addr = mmap(NULL, *length, PROT_READ, MAP_PRIVATE, fd, 0);
282 } else {
283 /* there will not be enough bytes after the file content mapping for the additional bytes and some of them
284 * would overflow into another page that would not be zerroed and any access into it would generate SIGBUS.
285 * Therefore we have to do the following hack with double mapping. First, the required number of bytes
286 * (including the additinal bytes) is required as anonymous and thus they will be really provided (actually more
287 * because of using whole pages) and also initialized by zeros. Then, the file is mapped to the same address
288 * where the anonymous mapping starts. */
289 *length = sb.st_size + pagesize;
290 *addr = mmap(NULL, *length, PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
291 *addr = mmap(*addr, sb.st_size, PROT_READ, MAP_PRIVATE | MAP_FIXED, fd, 0);
292 }
293 if (*addr == MAP_FAILED) {
294 LOGERR(ctx, LY_ESYS, "mmap() failed (%s).", strerror(errno));
295 return LY_ESYS;
Michal Vasko841d1a92018-09-07 15:40:31 +0200296 }
297
Radek Krejcif345c012018-09-19 11:12:59 +0200298 return LY_SUCCESS;
Radek Krejci86d106e2018-10-18 09:53:19 +0200299}
Michal Vasko841d1a92018-09-07 15:40:31 +0200300
Radek Krejci86d106e2018-10-18 09:53:19 +0200301LY_ERR
302ly_munmap(void *addr, size_t length)
303{
304 if (munmap(addr, length)) {
305 return LY_ESYS;
306 }
307 return LY_SUCCESS;
Michal Vasko841d1a92018-09-07 15:40:31 +0200308}
Radek Krejci4f28eda2018-11-12 11:46:16 +0100309
310LY_ERR
Radek Krejci249973a2019-06-10 10:50:54 +0200311ly_parse_int(const char *val_str, size_t val_len, int64_t min, int64_t max, int base, int64_t *ret)
Radek Krejci4f28eda2018-11-12 11:46:16 +0100312{
313 char *strptr;
314
Radek Krejci249973a2019-06-10 10:50:54 +0200315 LY_CHECK_ARG_RET(NULL, val_str, val_str[0], val_len, LY_EINVAL);
Radek Krejci4f28eda2018-11-12 11:46:16 +0100316
317 /* convert to 64-bit integer, all the redundant characters are handled */
318 errno = 0;
319 strptr = NULL;
320
321 /* parse the value */
322 *ret = strtoll(val_str, &strptr, base);
Radek Krejci249973a2019-06-10 10:50:54 +0200323 if (errno || strptr == val_str) {
Radek Krejci4f28eda2018-11-12 11:46:16 +0100324 return LY_EVALID;
325 } else if ((*ret < min) || (*ret > max)) {
326 return LY_EDENIED;
327 } else if (strptr && *strptr) {
328 while (isspace(*strptr)) {
329 ++strptr;
330 }
Radek Krejci249973a2019-06-10 10:50:54 +0200331 if (*strptr && strptr < val_str + val_len) {
Radek Krejci4f28eda2018-11-12 11:46:16 +0100332 return LY_EVALID;
333 }
334 }
335 return LY_SUCCESS;
336}
337
338LY_ERR
Radek Krejci249973a2019-06-10 10:50:54 +0200339ly_parse_uint(const char *val_str, size_t val_len, uint64_t max, int base, uint64_t *ret)
Radek Krejci4f28eda2018-11-12 11:46:16 +0100340{
341 char *strptr;
342 uint64_t u;
343
344 LY_CHECK_ARG_RET(NULL, val_str, val_str[0], LY_EINVAL);
345
346 errno = 0;
347 strptr = NULL;
348 u = strtoull(val_str, &strptr, base);
Radek Krejci249973a2019-06-10 10:50:54 +0200349 if (errno || strptr == val_str) {
Radek Krejci4f28eda2018-11-12 11:46:16 +0100350 return LY_EVALID;
351 } else if ((u > max) || (u && val_str[0] == '-')) {
352 return LY_EDENIED;
353 } else if (strptr && *strptr) {
354 while (isspace(*strptr)) {
355 ++strptr;
356 }
Radek Krejci249973a2019-06-10 10:50:54 +0200357 if (*strptr && strptr < val_str + val_len) {
Radek Krejci4f28eda2018-11-12 11:46:16 +0100358 return LY_EVALID;
359 }
Radek Krejci249973a2019-06-10 10:50:54 +0200360 } else if (u != 0 && val_str[0] == '-') {
361 return LY_EDENIED;
Radek Krejci4f28eda2018-11-12 11:46:16 +0100362 }
363
364 *ret = u;
365 return LY_SUCCESS;
366}