1 /*
2 *
3 ***** BEGIN LICENSE BLOCK *****
4
5 Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren
6 Copyright (C) 2017-2019 Olof Hagsand
7 Copyright (C) 2020 Olof Hagsand and Rubicon Communications, LLC(Netgate)
8
9 This file is part of CLIXON.
10
11 Licensed under the Apache License, Version 2.0 (the "License");
12 you may not use this file except in compliance with the License.
13 You may obtain a copy of the License at
14
15 http://www.apache.org/licenses/LICENSE-2.0
16
17 Unless required by applicable law or agreed to in writing, software
18 distributed under the License is distributed on an "AS IS" BASIS,
19 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20 See the License for the specific language governing permissions and
21 limitations under the License.
22
23 Alternatively, the contents of this file may be used under the terms of
24 the GNU General Public License Version 3 or later (the "GPL"),
25 in which case the provisions of the GPL are applicable instead
26 of those above. If you wish to allow use of your version of this file only
27 under the terms of the GPL, and not to allow others to
28 use your version of this file under the terms of Apache License version 2,
29 indicate your decision by deleting the provisions above and replace them with
30 the notice and other provisions required by the GPL. If you do not delete
31 the provisions above, a recipient may use your version of this file under
32 the terms of any one of the Apache License version 2 or the GPL.
33
34 ***** END LICENSE BLOCK *****
35
36 * Yang type related functions
37 * Part of this is type resolving which is pretty complex
38 * +--> yang_type_cache_set
39 * (called at parse) |
40 * ys_resolve_type --+ ys_populate_range, yang_enum_int_value(NULL)
41 * \ | cml
42 * v v v
43 * yang_type_get --> yang_type_resolve --> resolve_restrictions
44 * (leaf(list) front) (recursive core fn) (regexps, length, ranges, ...)
45 * ^ ^ ^ ^
46 * | | | |
47 * | yang2cli_var | yang2cli_var_union_one
48 * ys_cv_validate---+ ys_cv_validate_union_one
49 * | \ /
50 * | \ / yang_type_cache_regex_set
51 * ys_populate_leaf, +--> compile_pattern2regexp (compile regexps)
52 * xml_cv_cache (NULL) +--> cv_validate1 --> cv_validate_pattern (exec regexps)
53 * yang_type2cv (simplified)
54 *
55 * NOTE
56 * 1) ys_cv_validate/ys_cv_validate_union_one and
57 * yang2cli_var/yang2cli_var_union_one can unify?
58 * 2) Cache of regex is set in ys_cv_validate - not in ys_reolve_parse
59 * This is because trees are copied in yang_parse_post after ys_reolve_type
60 * is called, and regexps (void*) cannot be copied (COMPLEX)
61 * 3) We know I think when cache is set and when it is not set in the calls
62 * to yang_type_resolve. maybe we should make code easier by a separate
63 * yang_type_resolve_cache() call?
64 */
65
66 #ifdef HAVE_CONFIG_H
67 #include "clixon_config.h" /* generated by config & autoconf */
68 #endif
69
70 #include <stdio.h>
71 #include <stdlib.h>
72 #include <errno.h>
73 #include <inttypes.h>
74 #include <limits.h>
75 #include <ctype.h>
76 #include <string.h>
77 #include <arpa/inet.h>
78 #include <regex.h>
79 #include <syslog.h>
80 #include <assert.h>
81 #include <regex.h>
82 #include <netinet/in.h>
83 #include <sys/param.h>
84
85 /* cligen */
86 #include <cligen/cligen.h>
87
88 /* clicon */
89 #include "clixon_log.h"
90 #include "clixon_err.h"
91 #include "clixon_string.h"
92 #include "clixon_queue.h"
93 #include "clixon_hash.h"
94 #include "clixon_handle.h"
95 #include "clixon_regex.h"
96 #include "clixon_hash.h"
97 #include "clixon_yang.h"
98 #include "clixon_xml.h"
99 #include "clixon_xml_nsctx.h"
100 #include "clixon_yang_module.h"
101 #include "clixon_plugin.h"
102 #include "clixon_options.h"
103 #include "clixon_yang_type.h"
104
105 /*
106 * Local types and variables
107 */
108
109 /* Mapping between yang types <--> cligen types
110 Note, first match used wne translating from cv to yang --> order is significant */
111 static const map_str2int ytmap[] = {
112 {"int32", CGV_INT32}, /* NOTE, first match on right is significant, dont move */
113 {"string", CGV_STRING}, /* NOTE, first match on right is significant, dont move */
114 {"string", CGV_REST}, /* For cv -> yang translation of rest */
115 {"binary", CGV_STRING},
116 {"bits", CGV_STRING},
117 {"boolean", CGV_BOOL},
118 {"decimal64", CGV_DEC64},
119 {"empty", CGV_VOID}, /* May not include any content */
120 {"enumeration", CGV_STRING},
121 {"identityref", CGV_STRING}, /* XXX */
122 {"instance-identifier", CGV_STRING}, /* XXX */
123 {"int8", CGV_INT8},
124 {"int16", CGV_INT16},
125 {"int64", CGV_INT64},
126 {"leafref", CGV_STRING}, /* XXX */
127 {"uint8", CGV_UINT8},
128 {"uint16", CGV_UINT16},
129 {"uint32", CGV_UINT32},
130 {"uint64", CGV_UINT64},
131 {"union", CGV_REST}, /* Is replaced by actual type */
132 {NULL, -1}
133 };
134
135 /*! Mapping from yang string types --> cligen types
136 * @note not 100% same as map_str2int since it has significant order AND
137 * string->CGV_REST entry removed
138 */
139 static const map_str2int ytmap2[] = {
140 {"binary", CGV_STRING},
141 {"bits", CGV_STRING},
142 {"boolean", CGV_BOOL},
143 {"decimal64", CGV_DEC64},
144 {"empty", CGV_VOID}, /* May not include any content */
145 {"enumeration", CGV_STRING},
146 {"identityref", CGV_STRING}, /* XXX */
147 {"instance-identifier", CGV_STRING}, /* XXX */
148 {"int16", CGV_INT16},
149 {"int32", CGV_INT32},
150 {"int64", CGV_INT64},
151 {"int8", CGV_INT8},
152 {"leafref", CGV_STRING}, /* XXX */
153 {"string", CGV_STRING},
154 {"uint16", CGV_UINT16},
155 {"uint32", CGV_UINT32},
156 {"uint64", CGV_UINT64},
157 {"uint8", CGV_UINT8},
158 {"union", CGV_REST}, /* Is replaced by actual type */
159 {NULL, -1}
160 };
161
162 /* return 1 if built-in, 0 if not */
163 static int
yang_builtin(char * type)164 yang_builtin(char *type)
165 {
166 if (clicon_str2int_search(ytmap2, type, (sizeof(ytmap)/sizeof(map_str2int))-2) != -1)
167 return 1;
168 return 0;
169 }
170
171 /*! Compile yang patterns in string form to regex compiled void* form
172 * and re-store into "patterns" cvec.
173 * This is done here instead of deep in resolve code (resolve_restrictions)
174 * since it id dependent on clicon_handle.
175 * The downside is that all accesses to "patterns" must pass via the cache.
176 * If calls to yang_type_resolve is made without the cache is set, will be
177 * wrong.
178 * @see match_regexp in cligen code
179 * @see yang_type_resolve_restrictions where patterns is set
180 */
181 static int
compile_pattern2regexp(clicon_handle h,cvec * patterns,cvec * regexps)182 compile_pattern2regexp(clicon_handle h,
183 cvec *patterns,
184 cvec *regexps)
185 {
186 int retval = -1;
187 cg_var *pcv; /* pattern cv */
188 cg_var *rcv; /* regexp cv */
189 void *re = NULL;
190 int ret;
191 char *pattern;
192
193 pcv = NULL;
194 while ((pcv = cvec_each(patterns, pcv)) != NULL){
195 pattern = cv_string_get(pcv);
196 /* Compile yang pattern. handle necessary to select regex engine */
197 if ((ret = regex_compile(h, pattern, &re)) < 0)
198 goto done;
199 if (ret == 0){
200 clicon_err(OE_YANG, errno, "regexp compile fail: \"%s\"",
201 pattern);
202 goto done;
203 break;
204 }
205 if ((rcv = cvec_add(regexps, CGV_VOID)) == NULL){
206 clicon_err(OE_UNIX, errno, "cvec_add");
207 goto done;
208 }
209 if (re != NULL)
210 cv_void_set(rcv, re);
211 re = NULL;
212 /* invert pattern check */
213 if (cv_flag(pcv, V_INVERT))
214 cv_flag_set(rcv, V_INVERT);
215 }
216 retval = 1;
217 done:
218 return retval;
219 }
220
221 /*! Resolve types: populate type caches
222 * @param[in] ys This is a type statement
223 * @param[in] arg Not used
224 * Typically only called once when loading te yang type system.
225 * @note unions not cached
226 */
227 int
ys_resolve_type(yang_stmt * ys,void * arg)228 ys_resolve_type(yang_stmt *ys,
229 void *arg)
230 {
231 // clicon_handle h = (clicon_handle)arg;
232 int retval = -1;
233 int options = 0x0;
234 cvec *cvv = NULL;
235 cvec *patterns = NULL;
236 uint8_t fraction = 0;
237 yang_stmt *resolved = NULL;
238
239 if (yang_keyword_get(ys) != Y_TYPE){
240 clicon_err(OE_YANG, EINVAL, "Expected Y_TYPE");
241 goto done;
242 }
243 if ((patterns = cvec_new(0)) == NULL){
244 clicon_err(OE_UNIX, errno, "cvec_new");
245 goto done;
246 }
247 /* Recursively resolve ys -> resolve with restrictions(options, etc)
248 * Note that the resolved type could be ys itself.
249 */
250 if (yang_type_resolve(yang_parent_get(ys), yang_parent_get(ys),
251 ys, &resolved,
252 &options, &cvv, patterns, NULL, &fraction) < 0)
253 goto done;
254
255 /* Cache the type resolving locally. Only place where this is done.
256 * Why not do it in yang_type_resolve? (compile regexps needs clicon_handle)
257 */
258 if (yang_type_cache_set(ys, resolved, options, cvv,
259 patterns, fraction) < 0)
260 goto done;
261 retval = 0;
262 done:
263 if (patterns)
264 cvec_free(patterns);
265 return retval;
266 }
267
268 /*! Translate from a yang type to a cligen variable type
269 *
270 * Currently many built-in types from RFC6020 and some RFC6991 types.
271 * But not all, neither built-in nor 6991.
272 * Also, there is no support for derived types, eg yang typedefs.
273 * See 4.2.4 in RFC6020
274 * Return 0 if no match but set cv_type to CGV_ERR
275 */
276 int
yang2cv_type(char * ytype,enum cv_type * cv_type)277 yang2cv_type(char *ytype,
278 enum cv_type *cv_type)
279 {
280 int ret;
281
282 *cv_type = CGV_ERR;
283 /* built-in types */
284 if ((ret = clicon_str2int_search(ytmap2, ytype, (sizeof(ytmap)/sizeof(map_str2int))-2)) != -1){
285 *cv_type = ret;
286 return 0;
287 }
288 return 0;
289 }
290
291 /*! Translate from a cligen variable type to a yang type
292 */
293 char *
cv2yang_type(enum cv_type cv_type)294 cv2yang_type(enum cv_type cv_type)
295 {
296 char *ytype;
297 const char *str;
298
299 ytype = "empty";
300 /* built-in types */
301 if ((str = clicon_int2str(ytmap, cv_type)) != NULL)
302 return (char*)str;
303
304 /* special derived types */
305 if (cv_type == CGV_IPV4ADDR) /* RFC6991 */
306 return "ipv4-address";
307
308 if (cv_type == CGV_IPV6ADDR) /* RFC6991 */
309 return "ipv6-address";
310
311 if (cv_type == CGV_IPV4PFX) /* RFC6991 */
312 return "ipv4-prefix";
313
314 if (cv_type == CGV_IPV6PFX) /* RFC6991 */
315 return "ipv6-prefix";
316
317 if (cv_type == CGV_TIME) /* RFC6991 */
318 return "date-and-time";
319
320 if (cv_type == CGV_MACADDR) /* RFC6991 */
321 return "mac-address";
322
323 if (cv_type == CGV_UUID) /* RFC6991 */
324 return "uuid";
325
326 return ytype;
327 }
328
329 /*! Translate from yang type -> cligen type, after yang resolve has been made.
330 * handle case where yang resolve did not succedd (rtype=NULL) and then try
331 * to find special cligen types such as ipv4addr.
332 * not true yang types
333 * @param[in] origtype Name of original type
334 * @param[in] restype Resolved type. May be null, in that case origtype is used
335 * @param[in] ys Yang stmt of original resolving node
336 * @param[out] cvtype Translation from resolved type
337 * @note Thereis a kludge for handling direct translations of native cligen types
338 */
339 int
clicon_type2cv(char * origtype,char * restype,yang_stmt * ys,enum cv_type * cvtype)340 clicon_type2cv(char *origtype,
341 char *restype,
342 yang_stmt *ys,
343 enum cv_type *cvtype)
344 {
345 int retval = -1;
346 yang_stmt *ym;
347
348 *cvtype = CGV_ERR;
349 ym = ys_module(ys);
350 if (restype != NULL){
351 yang2cv_type(restype, cvtype);
352 if (*cvtype == CGV_ERR){
353 clicon_err(OE_YANG, 0, "%s: \"%s\" type not translated",
354 yang_argument_get(ym), restype);
355 goto done;
356 }
357 }
358 else{
359 /*
360 * Not resolved, but we can use special cligen types, eg ipv4addr
361 * Note this is a kludge or at least if we intend of using rfc types
362 */
363 yang2cv_type(origtype, cvtype);
364 if (*cvtype == CGV_ERR){
365 clicon_err(OE_YANG, 0, "%s:\"%s\": type not resolved",
366 yang_argument_get(ym), origtype);
367 goto done;
368 }
369 }
370 retval = 0;
371 done:
372 return retval;
373 }
374
375 /*! Validate CLIgen variable with pattern statements
376 * @param[in] h Clicon handle
377 * @param[in] regexps Vector of compiled regexps
378 * @param[out] reason If given, and return value is 0, contains malloced string
379 * @retval -1 Error (fatal), with errno set to indicate error
380 * @retval 0 Validation not OK, malloced reason is returned. Free reason with free()
381 * @retval 1 Validation OK
382 */
383 static int
cv_validate_pattern(clicon_handle h,cvec * regexps,yang_stmt * yrestype,char * str,char ** reason)384 cv_validate_pattern(clicon_handle h,
385 cvec *regexps,
386 yang_stmt *yrestype,
387 char *str,
388 char **reason)
389 {
390 int retval = -1;
391 cg_var *cvr;
392 void *re = NULL;
393 int ret;
394
395 cvr = NULL; /* Loop over compiled regexps */
396 while ((cvr = cvec_each(regexps, cvr)) != NULL){
397 re = cv_void_get(cvr);
398 if ((ret = regex_exec(h, re, str?str:"")) < 0)
399 goto done;
400 if (cv_flag(cvr, V_INVERT))
401 ret = !ret; /* swap 0 and 1 */
402 if (ret == 0){
403 if (reason)
404 *reason = cligen_reason("regexp match fail: pattern does not match %s",
405 str);
406 goto fail;
407 break;
408 }
409 }
410 retval = 1; /* match */
411 done:
412 return retval;
413 fail:
414 retval = 0; /* validation failed */
415 goto done;
416
417 }
418
419 /* cf cligen/cligen_var.c */
420 #define range_check(i, rmin, rmax, type) \
421 ((rmin && (i) < cv_##type##_get(rmin)) || \
422 (rmax && (i) > cv_##type##_get(rmax)))
423
424
425 /*! Error messsage for int violating ranges
426 * @note contains kludge - duplicate loop
427 */
428 static int
outofrange(cg_var * cv0,cvec * cvv,char ** reason)429 outofrange(cg_var *cv0,
430 cvec *cvv,
431 char **reason)
432 {
433 int retval = -1;
434 cbuf *cb = NULL;
435 cg_var *cv1;
436 cg_var *cv2;
437 int i;
438
439 if ((cb = cbuf_new()) == NULL)
440 goto done;
441 cprintf(cb, "Number ");
442 cv2cbuf(cv0, cb);
443 cprintf(cb, " out of range: ");
444 /* Kludge: need to repeat the same loop as in the main function in
445 cv_validate1 */
446 i = 0;
447 while (i<cvec_len(cvv)){
448 cv1 = cvec_i(cvv, i++); /* Increment to check for max pair */
449 if (strcmp(cv_name_get(cv1),"range_min") != 0){
450 clicon_err(OE_YANG, EINVAL, "Internal error, expected range_min");
451 goto done;
452 }
453 if (i<cvec_len(cvv) &&
454 (cv2 = cvec_i(cvv, i)) != NULL &&
455 strcmp(cv_name_get(cv2),"range_max") == 0){
456 i++;
457 }
458 else
459 cv2 = cv1;
460 if (i>2)
461 cprintf(cb, ", ");
462 cv2cbuf(cv1, cb);
463 cprintf(cb, " - ");
464 cv2cbuf(cv2, cb);
465 }
466 if (reason && (*reason = strdup(cbuf_get(cb))) == NULL)
467 goto done;
468 if (cb)
469 cbuf_free(cb);
470 retval = 0;
471 done:
472 return retval;
473 }
474
475 /*! Error messsage for string violating string limits
476 * @note contains kludge - duplicate loop
477 */
478 static int
outoflength(uint64_t u64,cvec * cvv,char ** reason)479 outoflength(uint64_t u64,
480 cvec *cvv,
481 char **reason)
482 {
483 int retval = -1;
484 cbuf *cb = NULL;
485 cg_var *cv1;
486 cg_var *cv2;
487 int i;
488
489 if ((cb = cbuf_new()) == NULL)
490 goto done;
491 cprintf(cb, "String length %" PRIu64 " out of range: ", u64);
492
493 /* Kludge: need to repeat the same loop as in the main function in
494 cv_validate1 */
495 i = 0;
496 while (i<cvec_len(cvv)){
497 cv1 = cvec_i(cvv, i++); /* Increment to check for max pair */
498 if (strcmp(cv_name_get(cv1),"range_min") != 0){
499 clicon_err(OE_YANG, EINVAL, "Internal error, expected range_min");
500 goto done;
501 }
502 if (i<cvec_len(cvv) &&
503 (cv2 = cvec_i(cvv, i)) != NULL &&
504 strcmp(cv_name_get(cv2),"range_max") == 0){
505 i++;
506 }
507 else
508 cv2 = cv1;
509 if (i>2)
510 cprintf(cb, ", ");
511 cv2cbuf(cv1, cb);
512 cprintf(cb, " - ");
513 cv2cbuf(cv2, cb);
514 }
515 if (reason && (*reason = strdup(cbuf_get(cb))) == NULL)
516 goto done;
517 if (cb)
518 cbuf_free(cb);
519 retval = 0;
520 done:
521 return retval;
522 }
523
524 /*! Validate CLIgen variable
525 * @param[in] h Clicon handle
526 * @param[in] cv A cligen variable to validate. This is a correctly parsed cv.
527 * @param[in] cvtype Resolved type of cv
528 * string describing reason why validation failed.
529 * @param[in] regexps Vector of compiled regexps
530 * @param[out] reason If given, and return value is 0, contains malloced str
531
532 * @retval -1 Error (fatal), with errno set to indicate error
533 * @retval 0 Validation not OK, malloced reason is returned. Free reason with free()
534 * @retval 1 Validation OK
535 * @note reason if given must be freed by caller
536 * @see cv_validate Corresponding type check in cligen
537 */
538 static int
cv_validate1(clicon_handle h,cg_var * cv,enum cv_type cvtype,int options,cvec * cvv,cvec * regexps,yang_stmt * yrestype,char * restype,char ** reason)539 cv_validate1(clicon_handle h,
540 cg_var *cv,
541 enum cv_type cvtype,
542 int options,
543 cvec *cvv,
544 cvec *regexps,
545 yang_stmt *yrestype,
546 char *restype,
547 char **reason)
548 {
549 int retval = 1; /* OK */
550 cg_var *cv1;
551 cg_var *cv2;
552 int ret;
553 yang_stmt *yi = NULL;
554 char *str = NULL;
555 int found;
556 char **vec = NULL;
557 int nvec;
558 char *v;
559 uint64_t uu = 0;
560 int64_t ii = 0;
561 int i;
562 int reti; /* must keep signed, unsigned and string retval */
563 int retu; /* separated due to different error handling */
564 int rets;
565
566 if (reason && *reason){
567 free(*reason);
568 *reason = NULL;
569 }
570 /* check options first for length and range */
571 if ((options & YANG_OPTIONS_RANGE) != 0 ||
572 (options & YANG_OPTIONS_LENGTH) != 0){
573 i = 0;
574 while (i<cvec_len(cvv)){
575 cv1 = cvec_i(cvv, i++); /* Increment to check for max pair */
576 if (strcmp(cv_name_get(cv1),"range_min") != 0){
577 clicon_err(OE_YANG, EINVAL, "Internal error, expected range_min");
578 goto done;
579 }
580 if (i<cvec_len(cvv) &&
581 (cv2 = cvec_i(cvv, i)) != NULL &&
582 strcmp(cv_name_get(cv2),"range_max") == 0){
583 i++;
584 }
585 else
586 cv2 = cv1;
587 reti = 0; retu = 0; rets = 0;
588 switch (cvtype){
589 case CGV_INT8:
590 ii = cv_int8_get(cv);
591 reti = range_check(ii, cv1, cv2, int8);
592 break;
593 case CGV_INT16:
594 ii = cv_int16_get(cv);
595 reti = range_check(ii, cv1, cv2, int16);
596 break;
597 case CGV_INT32:
598 ii = cv_int32_get(cv);
599 reti = range_check(ii, cv1, cv2, int32);
600 break;
601 case CGV_DEC64: /* XXX look at fraction-digit? */
602 case CGV_INT64:
603 ii = cv_int64_get(cv);
604 reti = range_check(ii, cv1, cv2, int64);
605 break;
606 case CGV_UINT8:
607 uu = cv_uint8_get(cv);
608 retu = range_check(uu, cv1, cv2, uint8);
609 break;
610 case CGV_UINT16:
611 uu = cv_uint16_get(cv);
612 retu = range_check(uu, cv1, cv2, uint16);
613 break;
614 case CGV_UINT32:
615 uu = cv_uint32_get(cv);
616 retu = range_check(uu, cv1, cv2, uint32);
617 break;
618 case CGV_UINT64:
619 uu = cv_uint32_get(cv);
620 retu = range_check(uu, cv1, cv2, uint64);
621 break;
622 case CGV_STRING:
623 case CGV_REST:
624 if ((str = cv_string_get(cv)) == NULL)
625 uu = 0; /* equal no string with empty string for range check */
626 else
627 uu = strlen(str);
628 rets = range_check(uu, cv1, cv2, uint64);
629 break;
630 default:
631 break;
632 }
633 /* Error handling for signed and unsigned, strings in switch
634 * OK: if check OK
635 * Failure: check fails and it is the last
636 */
637 if ((reti==0 && retu==0 && rets == 0))
638 goto step1ok;
639 /* Check fails */
640 if (i==cvec_len(cvv)){ /* And it is last */
641 if (reason){
642 if (reti || retu){
643 if (outofrange(cv, cvv, reason) < 0)
644 goto done;
645 }
646 else
647 if (outoflength(uu, cvv, reason) < 0)
648 goto done;
649 }
650 goto fail;
651 }
652 } /* while i<cvec_len(cvv) */
653 }
654 step1ok:
655 /* then check options for others */
656 switch (cvtype){
657 case CGV_STRING:
658 case CGV_REST:
659 str = cv_string_get(cv);
660 /* Note, if there is no value, eg <s/>, str is NULL.
661 */
662 if (restype){
663 if (strcmp(restype, "enumeration") == 0){
664 found = 0;
665 yi = NULL;
666 if (str != NULL) {
667 // str = clixon_trim2(str, " \t\n"); /* May be misplaced, strip earlier? */
668 while ((yi = yn_each(yrestype, yi)) != NULL){
669 if (yang_keyword_get(yi) != Y_ENUM)
670 continue;
671 if (strcmp(yang_argument_get(yi), str) == 0){
672 found++;
673 break;
674 }
675 }
676 }
677 if (!found){
678 if (reason)
679 *reason = cligen_reason("'%s' does not match enumeration", str);
680 goto fail;
681 }
682 }
683 if (strcmp(restype, "bits") == 0 && str != NULL){
684 /* The lexical representation of the bits type is a space-separated list
685 * of the names of the bits that are set. A zero-length string thus
686 * represents a value where no bits are set.
687 */
688 str = clixon_trim2(str, " \t\n"); /* May be misplaced, strip earlier? */
689 nvec = 0;
690 if ((vec = clicon_strsep(str, " \t", &nvec)) == NULL)
691 goto done;
692 for (i=0; i<nvec; i++){
693 if ((v = vec[i]) == NULL || !strlen(v))
694 continue;
695 found = 0;
696 yi = NULL;
697 while ((yi = yn_each(yrestype, yi)) != NULL){
698 if (yang_keyword_get(yi) != Y_BIT)
699 continue;
700 if (strcmp(yang_argument_get(yi), v) == 0){
701 found++;
702 break;
703 }
704 }
705 if (!found){
706 if (reason)
707 *reason = cligen_reason("'%s' does not match enumeration", v);
708 goto fail;
709 break;
710 }
711 }
712 }
713 }
714 if (regexps && cvec_len(regexps)) {
715 if ((ret = cv_validate_pattern(h, regexps, yrestype, str, reason)) < 0)
716 goto done;
717 if (ret == 0)
718 goto fail;
719 }
720 break;
721 case CGV_VOID:
722 break; /* empty type OK */
723 case CGV_ERR:
724 retval = 0;
725 if (reason)
726 *reason = cligen_reason("Invalid cv");
727 goto fail;
728 break;
729 default:
730 break;
731 }
732 retval = 1; /* validation OK */
733 done:
734 if (vec)
735 free(vec);
736 return retval;
737 fail:
738 retval = 0; /* validation failed */
739 goto done;
740 }
741
742 /* Forward */
743 static int ys_cv_validate_union(clicon_handle h,yang_stmt *ys, char **reason,
744 yang_stmt *yrestype, char *type, char *val);
745
746 /*!
747 * @param[out] reason If given and return val is 0, contains a malloced string
748 * @retval -1 Error (fatal), with errno set to indicate error
749 * @retval 0 Validation not OK, malloced reason is returned. Free reason with free()
750 * @retval 1 Validation OK
751 */
752 static int
ys_cv_validate_union_one(clicon_handle h,yang_stmt * ys,char ** reason,yang_stmt * yt,char * type,char * val)753 ys_cv_validate_union_one(clicon_handle h,
754 yang_stmt *ys,
755 char **reason,
756 yang_stmt *yt,
757 char *type, /* orig type */
758 char *val)
759 {
760 int retval = -1;
761 yang_stmt *yrt; /* union subtype */
762 int options = 0;
763 cvec *cvv = NULL;
764 cvec *regexps = NULL;
765 cvec *patterns = NULL;
766 uint8_t fraction = 0;
767 char *restype;
768 enum cv_type cvtype;
769 cg_var *cvt=NULL;
770
771 if ((regexps = cvec_new(0)) == NULL){
772 clicon_err(OE_UNIX, errno, "cvec_new");
773 goto done;
774 }
775 if ((patterns = cvec_new(0)) == NULL){
776 clicon_err(OE_UNIX, errno, "cvec_new");
777 goto done;
778 }
779 if (yang_type_resolve(ys, ys, yt, &yrt, &options, &cvv, patterns, regexps,
780 &fraction) < 0)
781 goto done;
782 restype = yrt?yang_argument_get(yrt):NULL;
783 if (restype && strcmp(restype, "union") == 0){ /* recursive union */
784 if ((retval = ys_cv_validate_union(h, ys, reason, yrt, type, val)) < 0)
785 goto done;
786 }
787 else {
788 if (clicon_type2cv(type, restype, ys, &cvtype) < 0)
789 goto done;
790 /* reparse value with the new type */
791 if ((cvt = cv_new(cvtype)) == NULL){
792 clicon_err(OE_UNIX, errno, "cv_new");
793 goto done;
794 }
795 if (val == NULL){ /* Fail validation on NULL */
796 retval = 0;
797 goto done;
798 }
799 if ((retval = cv_parse1(val, cvt, reason)) < 0){
800 clicon_err(OE_UNIX, errno, "cv_parse");
801 goto done;
802 }
803 if (retval == 0)
804 goto done;
805 /* The regexp cache may be invalidated, in that case re-compile
806 * eg due to copying
807 */
808 if (cvec_len(patterns)!=0 && cvec_len(regexps)==0){
809 if (compile_pattern2regexp(h, patterns, regexps) < 1)
810 goto done;
811 if (yang_type_cache_regexp_set(yt,
812 clicon_yang_regexp(h),
813 regexps) < 0)
814 goto done;
815 }
816 if ((retval = cv_validate1(h, cvt, cvtype, options, cvv,
817 regexps, yrt, restype, reason)) < 0)
818 goto done;
819 }
820 done:
821 if (patterns)
822 cvec_free(patterns);
823 if (regexps)
824 cvec_free(regexps);
825 if (cvt)
826 cv_free(cvt);
827 return retval;
828 }
829
830 /*! Validate union
831 * @param[out] reason If given, and return value is 0, contains malloced string
832 * @retval -1 Error (fatal), with errno set to indicate error
833 * @retval 0 Validation not OK, malloced reason is returned. Free reason with free()
834 * @retval 1 Validation OK
835 */
836 static int
ys_cv_validate_union(clicon_handle h,yang_stmt * ys,char ** reason,yang_stmt * yrestype,char * type,char * val)837 ys_cv_validate_union(clicon_handle h,
838 yang_stmt *ys,
839 char **reason,
840 yang_stmt *yrestype,
841 char *type, /* orig type */
842 char *val)
843 {
844 int retval = 1; /* valid */
845 yang_stmt *yt = NULL;
846 char *reason1 = NULL; /* saved reason */
847
848 while ((yt = yn_each(yrestype, yt)) != NULL){
849 if (yang_keyword_get(yt) != Y_TYPE)
850 continue;
851 if ((retval = ys_cv_validate_union_one(h, ys, reason, yt, type, val)) < 0)
852 goto done;
853 /* If validation failed, save reason, reset error and continue,
854 * save latest reason if noithing validates.
855 */
856 if (retval == 0 && reason && *reason != NULL){
857 if (reason1)
858 free(reason1);
859 reason1 = *reason;
860 *reason = NULL;
861 }
862 if (retval == 1) /* Enough that one type validates value */
863 break;
864 }
865 done:
866 if (retval == 0 && reason1){
867 *reason = reason1;
868 reason1 = NULL;
869 }
870 if (reason1)
871 free(reason1);
872 return retval;
873 }
874
875 /*! Validate cligen variable cv using yang statement as spec
876 *
877 * @param[in] h Clicon handle
878 * @param[in] cv A cligen variable to validate. This is a correctly parsed cv.
879 * @param[in] ys A yang statement, must be leaf or leaf-list.
880 * @param[out] reason If given, and if return value is 0, contains malloced
881 * string describing reason why validation failed.
882 * @retval -1 Error (fatal), with errno set to indicate error
883 * @retval 0 Validation not OK, malloced reason is returned. Free reason with free()
884 * @retval 1 Validation OK
885 * See also cv_validate - the code is similar.
886 * @note reason if given must be freed by caller
887 */
888 int
ys_cv_validate(clicon_handle h,cg_var * cv,yang_stmt * ys,char ** reason)889 ys_cv_validate(clicon_handle h,
890 cg_var *cv,
891 yang_stmt *ys,
892 char **reason)
893 {
894 int retval = -1;
895 cg_var *ycv; /* cv of yang-statement */
896 int options = 0;
897 cvec *cvv = NULL;
898 cvec *patterns = NULL;
899 cvec *regexps = NULL;
900 enum cv_type cvtype;
901 char *origtype = NULL; /* orig type */
902 yang_stmt *yrestype; /* resolved type */
903 char *restype;
904 uint8_t fraction = 0;
905 int retval2;
906 char *val;
907 cg_var *cvt=NULL;
908
909 if (reason)
910 *reason=NULL;
911 if (yang_keyword_get(ys) != Y_LEAF && yang_keyword_get(ys) != Y_LEAF_LIST){
912 retval = 1;
913 goto done;
914 }
915 ycv = yang_cv_get(ys);
916 if ((regexps = cvec_new(0)) == NULL){
917 clicon_err(OE_UNIX, errno, "cvec_new");
918 goto done;
919 }
920 if ((patterns = cvec_new(0)) == NULL){
921 clicon_err(OE_UNIX, errno, "cvec_new");
922 goto done;
923 }
924 if (yang_type_get(ys, &origtype, &yrestype,
925 &options, &cvv,
926 patterns, regexps,
927 &fraction) < 0)
928 goto done;
929 restype = yrestype?yang_argument_get(yrestype):NULL;
930 if (clicon_type2cv(origtype, restype, ys, &cvtype) < 0)
931 goto done;
932
933 if (cv_type_get(ycv) != cvtype){
934 /* special case: dbkey has rest syntax-> cv but yang cant have that */
935 if (cvtype == CGV_STRING && cv_type_get(ycv) == CGV_REST)
936 ;
937 else {
938 clicon_err(OE_DB, 0, "Type mismatch data:%s != yang:%s",
939 cv_type2str(cvtype), cv_type2str(cv_type_get(ycv)));
940 goto done;
941 }
942 }
943 /* Note restype can be NULL here for example with unresolved hardcoded uuid */
944 if (restype && strcmp(restype, "union") == 0){
945 assert(cvtype == CGV_REST);
946 /* Instead of NULL, give an empty string to validate, this is to avoid cv_parse
947 * errors and may actually be the wrong thing to do.
948 */
949 if ((val = cv_string_get(cv)) == NULL)
950 val = "";
951 if ((retval2 = ys_cv_validate_union(h, ys, reason, yrestype, origtype, val)) < 0)
952 goto done;
953 retval = retval2; /* invalid (0) with latest reason or valid 1 */
954 }
955 else{
956 /* The regexp cache may be invalidated, in that case re-compile
957 * eg due to copying
958 */
959 if (cvec_len(patterns)!=0 && cvec_len(regexps)==0){
960 yang_stmt *yt;
961 if (compile_pattern2regexp(h, patterns, regexps) < 1)
962 goto done;
963 yt = yang_find(ys, Y_TYPE, NULL);
964 if (yang_type_cache_regexp_set(yt,
965 clicon_yang_regexp(h),
966 regexps) < 0)
967 goto done;
968 }
969 if ((retval = cv_validate1(h, cv, cvtype, options, cvv,
970 regexps, yrestype, restype, reason)) < 0)
971 goto done;
972 }
973 done:
974 if (origtype)
975 free(origtype);
976 if (regexps)
977 cvec_free(regexps);
978 if (patterns)
979 cvec_free(patterns);
980 if (cvt)
981 cv_free(cvt);
982 return retval;
983 }
984
985 /*
986 * a typedef can be under module, submodule, container, list, grouping, rpc,
987 * input, output, notification
988 */
989 static inline int
ys_typedef(yang_stmt * ys)990 ys_typedef(yang_stmt *ys)
991 {
992 return yang_keyword_get(ys) == Y_MODULE || yang_keyword_get(ys) == Y_SUBMODULE ||
993 yang_keyword_get(ys) == Y_CONTAINER || yang_keyword_get(ys) == Y_LIST;
994 }
995
996 /* find next ys up which can contain a typedef */
997 static yang_stmt *
ys_typedef_up(yang_stmt * ys)998 ys_typedef_up(yang_stmt *ys)
999 {
1000 yang_stmt *yn;
1001
1002 while (ys != NULL && !ys_typedef(ys)){
1003 yn = yang_parent_get(ys);
1004 /* Some extra stuff to ensure ys is a stmt */
1005 if (yn && yang_keyword_get(yn) == Y_SPEC)
1006 yn = NULL;
1007 ys = (yang_stmt*)yn;
1008 }
1009 /* Here it is either NULL or is a typedef-kind yang-stmt */
1010 return (yang_stmt*)ys;
1011 }
1012
1013 /*! Find identity yang-stmt given a name and a yang statement for prefix context
1014 *
1015 * @param[in] ys Yang spec of id statement
1016 * @param[in] identity Identity string on the form <prefix>:<id>
1017 * @retval yid yang-stmt of type IDENTITY
1018 * @retval NULL Not found
1019 * @see validate_identityref for (2) above
1020 * @see xml_find_identity
1021 */
1022 yang_stmt *
yang_find_identity(yang_stmt * ys,char * identity)1023 yang_find_identity(yang_stmt *ys,
1024 char *identity)
1025 {
1026 char *id = NULL;
1027 char *prefix = NULL;
1028 yang_stmt *ymodule;
1029 yang_stmt *yid = NULL;
1030 yang_stmt *yn;
1031
1032 if (nodeid_split(identity, &prefix, &id) < 0)
1033 goto done;
1034 /* No, now check if identityref is derived from base */
1035 if (prefix){ /* Go to top and find import that matches */
1036 if ((ymodule = yang_find_module_by_prefix(ys, prefix)) == NULL)
1037 goto done;
1038 /* if ymodule is a sub-module, the identity may be found in a
1039 * sub-module of ymod */
1040 yid = yang_find(ymodule, Y_IDENTITY, id);
1041 }
1042 else{
1043 while (1){
1044 /* Check upwards in hierarchy for matching typedefs */
1045 if ((ys = ys_typedef_up(ys)) == NULL) /* If reach top */
1046 break;
1047 /* Here find identity */
1048 if ((yid = yang_find(ys, Y_IDENTITY, id)) != NULL)
1049 break;
1050 /* Did not find a matching typedef there, proceed to next level */
1051 yn = yang_parent_get(ys);
1052 if (yn && yang_keyword_get(yn) == Y_SPEC)
1053 yn = NULL;
1054 ys = (yang_stmt*)yn;
1055 }
1056 }
1057 done:
1058 if (id)
1059 free(id);
1060 if (prefix)
1061 free(prefix);
1062 return yid;
1063 }
1064
1065 /*! Find identity yang-stmt given a name and a xml node for prefix context
1066 *
1067 * @param[in] yspec Top-level yang-spec
1068 * @param[in] identity Identity string on the form <prefix>:<id>
1069 * @param[in] nsc Namespace context for <prefix>
1070 * @retval yid yang-stmt of type IDENTITY
1071 * @retval NULL Not found
1072 * @see validate_identityref for (2) above
1073 * @see xml_find_identity
1074 */
1075 yang_stmt *
yang_find_identity_nsc(yang_stmt * yspec,char * identity,cvec * nsc)1076 yang_find_identity_nsc(yang_stmt *yspec,
1077 char *identity,
1078 cvec *nsc)
1079 {
1080 char *id = NULL;
1081 char *prefix = NULL;
1082 yang_stmt *ymodule;
1083 yang_stmt *yid = NULL;
1084 char *ns = NULL;
1085
1086 if (nodeid_split(identity, &prefix, &id) < 0)
1087 goto done;
1088 if ((ns = xml_nsctx_get(nsc, prefix)) == NULL)
1089 goto done;
1090 if ((ymodule = yang_find_module_by_namespace(yspec, ns)) == NULL)
1091 goto done;
1092 /* if ymodule is a sub-module, the identity may be found in a
1093 * sub-module of ymod */
1094 yid = yang_find(ymodule, Y_IDENTITY, id);
1095 done:
1096 if (id)
1097 free(id);
1098 if (prefix)
1099 free(prefix);
1100 return yid;
1101 }
1102
1103 /*! Resolve type restrictions, return constraining parameters
1104 *
1105 * This is for types with range/length/regexp restrictions of the base type
1106 * Also fraction-digits for decimal64 is handled as that.
1107 * @param[in] ytype yang-stmt object containing currently resolving type
1108 * @param[out] options Pointer to flags field of optional values. optional
1109 * @param[out] cvv Pointer to cvec with min range or length.
1110 * If options&YANG_OPTIONS_RANGE or YANG_OPTIONS_LENGTH
1111 * @param[out] regexps Pointer to cvec of compiled patterns
1112 * @param[out] fraction For decimal64, how many digits after period
1113 * @retval -1 Error
1114 * @retval 0 OK.
1115 */
1116 static int
yang_type_resolve_restrictions(yang_stmt * ytype,int * options,cvec ** cvv,cvec * regexps,uint8_t * fraction)1117 yang_type_resolve_restrictions(yang_stmt *ytype,
1118 int *options,
1119 cvec **cvv,
1120 cvec *regexps,
1121 uint8_t *fraction)
1122 {
1123 int retval = -1;
1124 yang_stmt *ys;
1125 cg_var *cv;
1126 char *pattern;
1127
1128 if (options && cvv &&
1129 (ys = yang_find(ytype, Y_RANGE, NULL)) != NULL){
1130 *cvv = yang_cvec_get(ys);
1131 *options |= YANG_OPTIONS_RANGE;
1132 }
1133 if (options && cvv &&
1134 (ys = yang_find(ytype, Y_LENGTH, NULL)) != NULL){
1135 *cvv = yang_cvec_get(ys);
1136 *options |= YANG_OPTIONS_LENGTH;
1137 }
1138 /* Find all patterns */
1139 if (options && regexps){
1140 ys = NULL;
1141 while ((ys = yn_each(ytype, ys)) != NULL) {
1142 if (yang_keyword_get(ys) != Y_PATTERN)
1143 continue;
1144 if ((cv = cvec_add(regexps, CGV_STRING)) == NULL){
1145 clicon_err(OE_UNIX, errno, "cvec_add");
1146 goto done;
1147 }
1148 pattern = yang_argument_get(ys); /* clear text pattern */
1149 /* Check 1.1 invert pattern */
1150 if (yang_find(ys, Y_MODIFIER, "invert-match") != NULL)
1151 cv_flag_set(cv, V_INVERT);
1152 cv_string_set(cv, pattern);
1153 }
1154 }
1155 if (options && fraction &&
1156 (ys = yang_find(ytype, Y_FRACTION_DIGITS, NULL)) != NULL){
1157 *fraction = cv_uint8_get(yang_cv_get(ys));
1158 *options |= YANG_OPTIONS_FRACTION_DIGITS;
1159 }
1160 retval = 0;
1161 done:
1162 return retval;
1163 }
1164
1165 /*! Recursively resolve a yang type to built-in type with optional restrictions
1166 * @param[in] yorig (original) type yang-stmt where original search is based
1167 * @param[in] ys (transitive) yang-stmt where current search is based
1168 * @param[in] ytype yang-stmt object containing currently resolving type
1169 * @param[out] yrestype Resolved type. return built-in type or NULL.
1170 * @param[out] options Flags field of optional values, see YANG_OPTIONS_*
1171 * @param[out] cvv Cvec with min/max range or length.
1172 * Present if options&YANG_OPTIONS_RANGE|_LENGTH.
1173 * Can be a vector if multiple ranges
1174 * @param[out] patterns Initialized cvec of regexp patterns strings (if any)
1175 * @param[out] regexps Initialized cvec of compiled regexps (if any)
1176 * @param[out] fraction for decimal64, how many digits after period
1177 * Present if options&YANG_OPTIONS_FRACTION_DIGITS
1178 * @retval 0 OK. Note yrestype may still be NULL.
1179 * @retval -1 Error, clicon_err handles errors
1180 * The setting of the options argument has the following semantics:
1181 * options&YANG_OPTIONS_RANGE or YANG_OPTIONS_LENGTH --> cvv is set containing
1182 * array of range_min, range_max cv:s
1183 * options&YANG_OPTIONS_FRACTION_DIGITS --> fraction is set
1184 * patterns && cvec_len(patterns) --> there are patterns
1185 * Note that the static output strings (type, pattern) should be copied if used asap.
1186 * Note also that for all pointer arguments, if NULL is given, no value is assigned.
1187 */
1188 int
yang_type_resolve(yang_stmt * yorig,yang_stmt * ys,yang_stmt * ytype,yang_stmt ** yrestype,int * options,cvec ** cvv,cvec * patterns,cvec * regexps,uint8_t * fraction)1189 yang_type_resolve(yang_stmt *yorig,
1190 yang_stmt *ys,
1191 yang_stmt *ytype,
1192 yang_stmt **yrestype,
1193 int *options,
1194 cvec **cvv,
1195 cvec *patterns,
1196 cvec *regexps,
1197 uint8_t *fraction)
1198 {
1199 yang_stmt *rytypedef = NULL; /* Resolved typedef of ytype */
1200 yang_stmt *rytype; /* Resolved type of ytype */
1201 char *type = NULL;
1202 char *prefix = NULL;
1203 int retval = -1;
1204 yang_stmt *yn;
1205 yang_stmt *yrmod; /* module where resolved type is looked for */
1206 int ret;
1207
1208 if (options)
1209 *options = 0x0;
1210 *yrestype = NULL; /* Initialization of resolved type that may not be necessary */
1211
1212 if (nodeid_split(yang_argument_get(ytype), &prefix, &type) < 0)
1213 goto done;
1214 /* Cache does not work for eg string length 32? */
1215 #if 1
1216 if ((ret = yang_type_cache_get(ytype, yrestype,
1217 options, cvv, patterns, NULL, regexps, fraction)) < 0)
1218 goto done;
1219 if (ret == 1)
1220 goto ok;
1221 #else
1222 if (ytype->ys_typecache != NULL){
1223 if (yang_type_cache_get(ytype, yrestype,
1224 options, cvv, patterns, NULL, regexps, fraction) < 0)
1225 goto done;
1226 goto ok;
1227 }
1228 #endif
1229 /* Check if type is basic type. If so, return that */
1230 if ((prefix == NULL && yang_builtin(type))){
1231 *yrestype = ytype;
1232 if (yang_type_resolve_restrictions(ytype, options, cvv, patterns, fraction) < 0)
1233 goto done;
1234 goto ok;
1235 }
1236
1237 /* Not basic type. Now check if prefix which means we look in other module */
1238 if (prefix){ /* Go to top and find import that matches */
1239 if ((yrmod = yang_find_module_by_prefix(ytype, prefix)) == NULL){
1240 clicon_err(OE_DB, 0, "Type not resolved: \"%s:%s\" in module %s",
1241 prefix, type, yang_argument_get(ys_module(yorig)));
1242 goto done;
1243 }
1244 if ((rytypedef = yang_find(yrmod, Y_TYPEDEF, type)) == NULL)
1245 goto ok; /* unresolved */
1246 ys = rytypedef;
1247 }
1248 else
1249 while (1){
1250 /* Check upwards in hierarchy for matching typedefs */
1251 if ((ys = ys_typedef_up(ys)) == NULL){ /* If reach top */
1252 *yrestype = NULL;
1253 break;
1254 }
1255 /* Here find typedef */
1256 if ((rytypedef = yang_find(ys, Y_TYPEDEF, type)) != NULL)
1257 break;
1258 /* Did not find a matching typedef there, proceed to next level */
1259 yn = yang_parent_get(ys);
1260 if (yn && (yang_keyword_get(yn) == Y_SPEC))
1261 yn = NULL;
1262 ys = (yang_stmt*)yn;
1263 }
1264 if (rytypedef != NULL){ /* We have found a typedef */
1265 /* Find associated type statement */
1266 if ((rytype = yang_find(rytypedef, Y_TYPE, NULL)) == NULL){
1267 clicon_err(OE_DB, 0, "mandatory type object is not found");
1268 goto done;
1269 }
1270 /* recursively resolve this new type */
1271 if (yang_type_resolve(yorig, ys, rytype, yrestype,
1272 options, cvv,
1273 patterns, regexps,
1274 fraction) < 0)
1275 goto done;
1276 /* appends patterns, overwrites others if any */
1277 if (yang_type_resolve_restrictions(ytype, options, cvv, patterns, fraction) < 0)
1278 goto done;
1279 }
1280 ok:
1281 retval = 0;
1282 done:
1283 if (prefix)
1284 free(prefix);
1285 if (type)
1286 free(type);
1287 return retval;
1288 }
1289
1290 /*! Get type information about a leaf/leaf-list yang-statement
1291 *
1292 * @code
1293 * yang_stmt *yrestype;
1294 * char *origtype = NULL;
1295 * int options;
1296 * cvec *cvv = NULL;
1297 * cvec *patterns = cvec_new(0);
1298 * cvec *regexps = cvec_new(0);
1299 * uint8_t fraction;
1300 *
1301 * if (yang_type_get(ys, &origtype, &yrestype, &options, &cvv,
1302 * patterns, regexps, &fraction) < 0)
1303 * goto err;
1304 * if (yrestype == NULL) # unresolved
1305 * goto err;
1306 * if (options & YANG_OPTIONS_LENGTH != 0)
1307 * printf("%d..%d\n", min , max);
1308 * @endcode
1309 * @param[in] ys yang-stmt, leaf or leaf-list
1310 * @param[out] origtype original type may be derived or built-in (malloced)
1311 * @param[out] yrestype Resolved type. return built-in type or NULL.
1312 * @param[out] options Flags field of optional values, see YANG_OPTIONS_*
1313 * @param[out] cvv Cvec with min/max range or length.
1314 * Present if options&YANG_OPTIONS_RANGE|_LENGTH.
1315 * Can be a vector if multiple ranges
1316 * @param[out] pattern yang cvec pattern POSIX regexp patterns
1317 * @param[out] regexps Initialized cvec of compiled regexps (if any)
1318 * @param[out] fraction for decimal64, how many digits after period
1319 * Present if options&YANG_OPTIONS_FRACTION_DIGITS
1320 * @retval 0 OK, but note that restype==NULL means not resolved.
1321 * @retval -1 Error, clicon_err handles errors
1322 * The setting of the options argument has the following semantics:
1323 * options&YANG_OPTIONS_RANGE or YANG_OPTIONS_LENGTH --> cvv is set containing
1324 * array of range_min, range_max cv:s
1325 * options&YANG_OPTIONS_FRACTION_DIGITS --> fraction is set
1326 * Note that the static output strings (type, pattern) should be copied if used asap.
1327 * Note also that for all pointer arguments, if NULL is given, no value is assigned.
1328 * @See yang_type_resolve(). This function is really just a frontend to that.
1329 */
1330 int
yang_type_get(yang_stmt * ys,char ** origtype,yang_stmt ** yrestype,int * options,cvec ** cvv,cvec * patterns,cvec * regexps,uint8_t * fraction)1331 yang_type_get(yang_stmt *ys,
1332 char **origtype,
1333 yang_stmt **yrestype,
1334 int *options,
1335 cvec **cvv,
1336 cvec *patterns,
1337 cvec *regexps,
1338 uint8_t *fraction
1339 )
1340 {
1341 int retval = -1;
1342 yang_stmt *ytype; /* type */
1343 char *type = NULL;
1344
1345 if (options)
1346 *options = 0x0;
1347 /* Find mandatory type */
1348 if ((ytype = yang_find(ys, Y_TYPE, NULL)) == NULL){
1349 clicon_err(OE_DB, ENOENT, "mandatory type object is not found");
1350 goto done;
1351 }
1352 /* XXX: here we seem to have some problems if type is union */
1353 if (nodeid_split(yang_argument_get(ytype), NULL, &type) < 0)
1354 goto done;
1355 if (origtype &&
1356 (*origtype = strdup(type)) == NULL){
1357 clicon_err(OE_XML, errno, "stdup");
1358 goto done;
1359 }
1360 if (yang_type_resolve(ys, ys, ytype, yrestype,
1361 options, cvv, patterns, regexps, fraction) < 0)
1362 goto done;
1363 retval = 0;
1364 done:
1365 if (type)
1366 free(type);
1367 return retval;
1368 }
1369
1370 /*! Utility function to translate a leaf/leaf-list to its base CV-type only
1371 * @see yang_type_get Full leaf/list type api
1372 */
1373 enum cv_type
yang_type2cv(yang_stmt * ys)1374 yang_type2cv(yang_stmt *ys)
1375 {
1376 yang_stmt *yrestype; /* resolved type */
1377 char *restype; /* resolved type */
1378 char *origtype=NULL; /* original type */
1379 enum cv_type cvtype = CGV_ERR;
1380
1381 /* Find type specification */
1382 if (yang_type_get(ys, &origtype, &yrestype, NULL, NULL, NULL, NULL, NULL)
1383 < 0)
1384 goto done;
1385 restype = yrestype?yang_argument_get(yrestype):NULL;
1386 if (clicon_type2cv(origtype, restype, ys, &cvtype) < 0) /* This handles non-resolved also */
1387 goto done;
1388 done:
1389 if (origtype)
1390 free(origtype);
1391 return cvtype;
1392 }
1393