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