1 /*
2  *
3   ***** BEGIN LICENSE BLOCK *****
4 
5   Copyright (C) 2009-2019 Olof Hagsand
6   Copyright (C) 2020 Olof Hagsand and Rubicon Communications, LLC(Netgate)
7 
8   This file is part of CLIXON.
9 
10   Licensed under the Apache License, Version 2.0 (the "License");
11   you may not use this file except in compliance with the License.
12   You may obtain a copy of the License at
13 
14     http://www.apache.org/licenses/LICENSE-2.0
15 
16   Unless required by applicable law or agreed to in writing, software
17   distributed under the License is distributed on an "AS IS" BASIS,
18   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19   See the License for the specific language governing permissions and
20   limitations under the License.
21 
22   Alternatively, the contents of this file may be used under the terms of
23   the GNU General Public License Version 3 or later (the "GPL"),
24   in which case the provisions of the GPL are applicable instead
25   of those above. If you wish to allow use of your version of this file only
26   under the terms of the GPL, and not to allow others to
27   use your version of this file under the terms of Apache License version 2,
28   indicate your decision by deleting the provisions above and replace them with
29   the  notice and other provisions required by the GPL. If you do not delete
30   the provisions above, a recipient may use your version of this file under
31   the terms of any one of the Apache License version 2 or the GPL.
32 
33   ***** END LICENSE BLOCK *****
34 
35  * Yang functions
36  * @see https://tools.ietf.org/html/rfc6020 YANG 1.0
37  * @see https://tools.ietf.org/html/rfc7950 YANG 1.1
38  */
39 
40 #ifdef HAVE_CONFIG_H
41 #include "clixon_config.h" /* generated by config & autoconf */
42 #endif
43 
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <errno.h>
47 #include <limits.h>
48 #include <ctype.h>
49 #include <unistd.h>
50 #include <string.h>
51 #include <arpa/inet.h>
52 #include <regex.h>
53 #include <dirent.h>
54 #include <sys/types.h>
55 #include <fcntl.h>
56 #include <syslog.h>
57 #include <assert.h>
58 #include <libgen.h>
59 #include <sys/stat.h>
60 #include <sys/param.h>
61 #include <netinet/in.h>
62 #include <libgen.h>
63 
64 /* cligen */
65 #include <cligen/cligen.h>
66 
67 /* clicon */
68 #include "clixon_log.h"
69 #include "clixon_err.h"
70 #include "clixon_string.h"
71 #include "clixon_queue.h"
72 #include "clixon_hash.h"
73 #include "clixon_handle.h"
74 #include "clixon_file.h"
75 #include "clixon_yang.h"
76 #include "clixon_hash.h"
77 #include "clixon_xml.h"
78 #include "clixon_xml_nsctx.h"
79 #include "clixon_yang_module.h"
80 #include "clixon_plugin.h"
81 #include "clixon_data.h"
82 #include "clixon_options.h"
83 #include "clixon_yang_parse.h"
84 #include "clixon_yang_parse_lib.h"
85 #include "clixon_yang_cardinality.h"
86 #include "clixon_yang_type.h"
87 #include "clixon_yang_internal.h" /* internal included by this file only, not API*/
88 
89 #ifdef XML_EXPLICIT_INDEX
90 static int yang_search_index_extension(clicon_handle h, yang_stmt *yext, yang_stmt *ys);
91 #endif
92 
93 /*
94  * Local variables
95  */
96 /* Mapping between yang keyword string <--> clicon constants
97  * Here is also the place where doc on some types store variables (cv)
98  */
99 static const map_str2int ykmap[] = {
100     {"anydata",          Y_ANYDATA},
101     {"anyxml",           Y_ANYXML},
102     {"argument",         Y_ARGUMENT},
103     {"augment",          Y_AUGMENT},
104     {"base",             Y_BASE},
105     {"belongs-to",       Y_BELONGS_TO},
106     {"bit",              Y_BIT},
107     {"case",             Y_CASE},
108     {"choice",           Y_CHOICE},
109     {"config",           Y_CONFIG},  /* cv: boolean config flag */
110     {"contact",          Y_CONTACT},
111     {"container",        Y_CONTAINER},
112     {"default",          Y_DEFAULT},
113     {"description",      Y_DESCRIPTION},
114     {"deviate",          Y_DEVIATE},
115     {"deviation",        Y_DEVIATION},
116     {"enum",             Y_ENUM},
117     {"error-app-tag",    Y_ERROR_APP_TAG},
118     {"error_message",    Y_ERROR_MESSAGE},
119     {"extension",        Y_EXTENSION},
120     {"feature",          Y_FEATURE},        /* cv: feature as boolean */
121     {"fraction-digits",  Y_FRACTION_DIGITS}, /* cv: fraction-digits as uint8 */
122     {"grouping",         Y_GROUPING},
123     {"identity",         Y_IDENTITY},
124     {"if-feature",       Y_IF_FEATURE},
125     {"import",           Y_IMPORT},
126     {"include",          Y_INCLUDE},
127     {"input",            Y_INPUT},
128     {"key",              Y_KEY},
129     {"leaf",             Y_LEAF},           /* cv: store default value (if any)*/
130     {"leaf-list",        Y_LEAF_LIST},      /* cv: store default value (if any)*/
131     {"length",           Y_LENGTH},
132     {"list",             Y_LIST},
133     {"mandatory",        Y_MANDATORY},      /* cv: store mandatory boolean */
134     {"max-elements",     Y_MAX_ELEMENTS},
135     {"min-elements",     Y_MIN_ELEMENTS},
136     {"modifier",         Y_MODIFIER},
137     {"module",           Y_MODULE},
138     {"must",             Y_MUST},
139     {"namespace",        Y_NAMESPACE},
140     {"notification",     Y_NOTIFICATION},
141     {"ordered-by",       Y_ORDERED_BY},
142     {"organization",     Y_ORGANIZATION},
143     {"output",           Y_OUTPUT},
144     {"path",             Y_PATH},
145     {"pattern",          Y_PATTERN},
146     {"position",         Y_POSITION},
147     {"prefix",           Y_PREFIX},
148     {"presence",         Y_PRESENCE},
149     {"range",            Y_RANGE},
150     {"reference",        Y_REFERENCE},
151     {"refine",           Y_REFINE},
152     {"require-instance", Y_REQUIRE_INSTANCE},
153     {"revision",         Y_REVISION},          /* cv: YYYY-MM-DD as uint32 */
154     {"revision-date",    Y_REVISION_DATE},     /* cv: YYYY-MM-DD as uint32 */
155     {"rpc",              Y_RPC},
156     {"status",           Y_STATUS},
157     {"submodule",        Y_SUBMODULE},
158     {"type",             Y_TYPE},
159     {"typedef",          Y_TYPEDEF},
160     {"unique",           Y_UNIQUE},
161     {"units",            Y_UNITS},
162     {"unknown",          Y_UNKNOWN},  /* cv: store extra string */
163     {"uses",             Y_USES},
164     {"value",            Y_VALUE},
165     {"when",             Y_WHEN},
166     {"yang-version",     Y_YANG_VERSION},
167     {"yin-element",      Y_YIN_ELEMENT},
168     {"yang-specification", Y_SPEC}, /* XXX: NOTE NOT YANG STATEMENT, reserved
169 				       for top level spec */
170     {NULL,               -1}
171 };
172 
173 /* Forward static */
174 static int yang_type_cache_free(yang_type_cache *ycache);
175 static int yang_type_cache_cp(yang_stmt *ynew, yang_stmt *yold);
176 
177 /* Access functions
178  */
179 
180 /*! Get Number of children yang statements
181  * @param[in] ys  Yang statement node
182  */
183 int
yang_len_get(yang_stmt * ys)184 yang_len_get(yang_stmt *ys)
185 {
186     return ys->ys_len;
187 }
188 
189 /*! Get Specific Yang statement child
190  * @param[in] ys  Yang statement node
191  * @param[in] i   Return this child
192  */
193 yang_stmt *
yang_child_i(yang_stmt * ys,int i)194 yang_child_i(yang_stmt *ys,
195 	     int        i)
196 {
197     return ys->ys_stmt[i];
198 }
199 
200 /*! Get yang statement parent
201  * @param[in] ys  Yang statement node
202  */
203 yang_stmt *
yang_parent_get(yang_stmt * ys)204 yang_parent_get(yang_stmt *ys)
205 {
206     return ys->ys_parent;
207 }
208 
209 /*! Get yang statement keyword
210  * @param[in] ys  Yang statement node
211  */
212 enum rfc_6020
yang_keyword_get(yang_stmt * ys)213 yang_keyword_get(yang_stmt *ys)
214 {
215     return ys->ys_keyword;
216 }
217 
218 /*! Get yang statement context-dependent argument
219  * @param[in] ys  Yang statement node
220  */
221 char*
yang_argument_get(yang_stmt * ys)222 yang_argument_get(yang_stmt *ys)
223 {
224     return ys->ys_argument;
225 }
226 
227 /*
228  * Note on cvec on XML nodes:
229  * 1. It is always created in xml_new. It could be lazily created on use to save a little memory
230  * 2. Only some yang statements use the cvec, as follows:
231  *  2a. ranges and lengths: [min, max]
232  *  2b. list: keys
233  *  2c. identity types: derived instances: identityrefs, save <module>:<idref>
234  *  2d. type: leafref types: derived instances.
235  */
236 /*! Set yang argument, not not copied
237  * @param[in] ys   Yang statement node
238  * @param[in] arg  Argument
239  * Typically only done at parsing / initiation
240  */
241 int
yang_argument_set(yang_stmt * ys,char * arg)242 yang_argument_set(yang_stmt *ys,
243 		  char      *arg)
244 {
245     ys->ys_argument = arg; /* not strdup/copied */
246     return 0;
247 }
248 
249 /*! Get yang statement CLIgen variable
250  * @param[in] ys  Yang statement node
251  */
252 cg_var*
yang_cv_get(yang_stmt * ys)253 yang_cv_get(yang_stmt *ys)
254 {
255     return ys->ys_cv;
256 }
257 
258 /*! Get yang statement CLIgen variable vector
259  * @param[in] ys  Yang statement node
260  */
261 cvec*
yang_cvec_get(yang_stmt * ys)262 yang_cvec_get(yang_stmt *ys)
263 {
264     return ys->ys_cvec;
265 }
266 
267 /*! Set yang statement CLIgen variable vector
268  * @param[in] ys   Yang statement node
269  * @param[in] cvec CLIgen vector
270  * @retval    0    OK
271  * @retval   -1    Error
272  */
273 int
yang_cvec_set(yang_stmt * ys,cvec * cvv)274 yang_cvec_set(yang_stmt *ys,
275 	      cvec      *cvv)
276 {
277     if (ys->ys_cvec)
278 	cvec_free(ys->ys_cvec);
279     ys->ys_cvec = cvv;
280     return 0;
281 }
282 
283 /*! Get yang stmt flags, used for internal algorithms
284  * @param[in]  ys     Yang statement
285  * @param[in]  flag   Flags value(s) to get, see YANG_FLAG_*
286  * @retval     value  Flags value masked by "flag" parameter, see YANG_FLAG_*
287  */
288 uint16_t
yang_flag_get(yang_stmt * ys,uint16_t flag)289 yang_flag_get(yang_stmt *ys,
290 	      uint16_t   flag)
291 {
292     return ys->ys_flags&flag;
293 }
294 
295 /*! Set yang stmt flags, used for internal algorithms
296  * @param[in]  ys     Yang statement
297  * @param[in]  flag   Flag value(s) to set, see YANG_FLAG_*
298  */
299 int
yang_flag_set(yang_stmt * ys,uint16_t flag)300 yang_flag_set(yang_stmt *ys,
301 	      uint16_t   flag)
302 {
303     ys->ys_flags |= flag;
304     return 0;
305 }
306 
307 /*! Reset yang stmt flags, used for internal algorithms
308  * @param[in]  ys     Yang statement
309  * @param[in]  flag   Flag value(s) to reset, see YANG_FLAG_*
310  */
311 int
yang_flag_reset(yang_stmt * ys,uint16_t flag)312 yang_flag_reset(yang_stmt *ys,
313 		uint16_t   flag)
314 {
315     ys->ys_flags &= ~flag;
316     return 0;
317 }
318 
319 /*! Get yang xpath for "when"-associated augment
320  *
321  * Ie, for yang structures like: augment <path> { when <xpath>; ... }
322  * Will insert new yang nodes at <path> with this special "when" struct (not yang node)
323  * @param[in]  ys     Yang statement
324  * @retval     xpath  xpath should evaluate to true at validation
325  * @retval     NULL   Not set
326  */
327 char*
yang_when_xpath_get(yang_stmt * ys)328 yang_when_xpath_get(yang_stmt *ys)
329 {
330     return  ys->ys_when_xpath;
331 }
332 
333 /*! Set yang xpath and namespace context for "when"-associated augment
334  *
335  * Ie, for yang structures like: augment <path> { when <xpath>; ... }
336  * Will insert new yang nodes at <path> with this special "when" struct (not yang node)
337  * @param[in]  ys     Yang statement
338  * @param[in]  xpath  If set, this xpath should evaluate to true at validation, copied
339  * @retval     0      OK
340  * @retval     -1     Error
341  */
342 int
yang_when_xpath_set(yang_stmt * ys,char * xpath)343 yang_when_xpath_set(yang_stmt *ys,
344 		    char      *xpath)
345 {
346     int retval = -1;
347 
348     if (xpath == NULL){
349 	clicon_err(OE_YANG, EINVAL, "xpath is NULL");
350 	goto done;
351     }
352     if ((ys->ys_when_xpath = strdup(xpath)) == NULL){
353 	clicon_err(OE_YANG, errno, "strdup");
354 	goto done;
355 
356     }
357     retval = 0;
358  done:
359     return retval;
360 }
361 
362 /*! Get yang namespace context for "when"-associated augment
363  *
364  * Ie, for yang structures like: augment <path> { when <xpath>; ... }
365  * Will insert new yang nodes at <path> with this special "when" struct (not yang node)
366  * @param[in]  ys     Yang statement
367  * @retval     nsc    Namespace context
368  * @note retval is direct pointer, may need to be copied
369  */
370 cvec *
yang_when_nsc_get(yang_stmt * ys)371 yang_when_nsc_get(yang_stmt *ys)
372 {
373     return ys->ys_when_nsc;
374 }
375 
376 /*! Set yang namespace context for "when"-associated augment
377  *
378  * Ie, for yang structures like: augment <path> { when <xpath>; ... }
379  * Will insert new yang nodes at <path> with this special "when" struct (not yang node)
380  * @param[in]  ys     Yang statement
381  * @param[in]  nsc    Namespace context for when xpath
382  * @retval     0      OK
383  * @retval     -1     Error
384  */
385 int
yang_when_nsc_set(yang_stmt * ys,cvec * nsc)386 yang_when_nsc_set(yang_stmt *ys,
387 		  cvec      *nsc)
388 {
389     int retval = -1;
390 
391     if (nsc && (ys->ys_when_nsc = cvec_dup(nsc)) == NULL){
392 	clicon_err(OE_YANG, errno, "cvec_dup");
393 	goto done;
394     }
395     retval = 0;
396  done:
397     return retval;
398 }
399 
400 /* End access functions */
401 
402 /*! Create new yang specification
403  * @retval  yspec    Free with yspec_free()
404  * @retval  NULL     Error
405  */
406 yang_stmt *
yspec_new(void)407 yspec_new(void)
408 {
409     yang_stmt *yspec;
410 
411     if ((yspec = malloc(sizeof(*yspec))) == NULL){
412 	clicon_err(OE_YANG, errno, "malloc");
413 	return NULL;
414     }
415     memset(yspec, 0, sizeof(*yspec));
416     yspec->ys_keyword = Y_SPEC;
417     return yspec;
418 }
419 
420 /*! Create new yang node/statement
421  * @retval  ys    Free with ys_free()
422  * @retval  NULL     Error
423  */
424 yang_stmt *
ys_new(enum rfc_6020 keyw)425 ys_new(enum rfc_6020 keyw)
426 {
427     yang_stmt *ys;
428     cvec      *cvv;
429 
430     if ((ys = malloc(sizeof(*ys))) == NULL){
431 	clicon_err(OE_YANG, errno, "malloc");
432 	return NULL;
433     }
434     memset(ys, 0, sizeof(*ys));
435     ys->ys_keyword    = keyw;
436     /* The cvec contains stmt-specific variables. Only few stmts need variables so the
437        cvec could be lazily created to save some heap and cycles. */
438     if ((cvv = cvec_new(0)) == NULL){
439 	clicon_err(OE_YANG, errno, "cvec_new");
440 	return NULL;
441     }
442     yang_cvec_set(ys, cvv);
443     return ys;
444 }
445 
446 /*! Free a single yang statement, dont remove children
447  *
448  * @param[in]  ys   Yang node to remove
449  * @param[in]  self Free own node
450  * @retval     0    OK
451  * @retval    -1    Error
452  * @see ys_free
453  */
454 static int
ys_free1(yang_stmt * ys,int self)455 ys_free1(yang_stmt *ys,
456 	 int        self)
457 {
458     if (ys->ys_argument){
459 	free(ys->ys_argument);
460 	ys->ys_argument = NULL;
461     }
462     if (ys->ys_cv){
463 	cv_free(ys->ys_cv);
464 	ys->ys_cv = NULL;
465     }
466     if (ys->ys_cvec){
467 	cvec_free(ys->ys_cvec);
468 	ys->ys_cvec = NULL;
469     }
470     if (ys->ys_typecache){
471 	yang_type_cache_free(ys->ys_typecache);
472 	ys->ys_typecache = NULL;
473     }
474     if (ys->ys_when_xpath)
475 	free(ys->ys_when_xpath);
476     if (ys->ys_when_nsc)
477 	cvec_free(ys->ys_when_nsc);
478     if (self)
479 	free(ys);
480     return 0;
481 }
482 
483 /*! Remove child i from parent yp (dont free)
484  * @param[in]  yp   Parent node
485  * @param[in]  i    Order of child to remove
486  * @retval     NULL No such node, nothing done
487  * @retval     yc   returned orphaned yang node
488  * @see ys_free Deallocate yang node
489  * @note Do not call this in a loop of yang children (unless you know what you are doing)
490  */
491 yang_stmt *
ys_prune(yang_stmt * yp,int i)492 ys_prune(yang_stmt *yp,
493 	 int        i)
494 {
495     size_t     size;
496     yang_stmt *yc = NULL;
497 
498     if (i >= yp->ys_len)
499 	goto done;
500     size = (yp->ys_len - i - 1)*sizeof(struct yang_stmt *);
501     yc = yp->ys_stmt[i];
502     memmove(&yp->ys_stmt[i],
503 	    &yp->ys_stmt[i+1],
504 	    size);
505     yp->ys_stmt[yp->ys_len--] = NULL;
506  done:
507     return yc;
508 }
509 
510 /*! Free a yang statement tree recursively
511  * @param[in]  ys   Yang node to remove and all its children recursively
512  * @note does not remove yang node from tree
513  * @see ys_prune  Remove from parent
514  */
515 int
ys_free(yang_stmt * ys)516 ys_free(yang_stmt *ys)
517 {
518     int i;
519     yang_stmt *yc;
520 
521     for (i=0; i<ys->ys_len; i++){
522 	if ((yc = ys->ys_stmt[i]) != NULL)
523 	    ys_free(yc);
524     }
525     if (ys->ys_stmt)
526 	free(ys->ys_stmt);
527     ys_free1(ys, 1);
528     return 0;
529 }
530 
531 /*! Free a yang specification recursively
532  */
533 int
yspec_free(yang_stmt * yspec)534 yspec_free(yang_stmt *yspec)
535 {
536     int i;
537     yang_stmt *ys;
538 
539     for (i=0; i<yspec->ys_len; i++){
540 	if ((ys = yspec->ys_stmt[i]) != NULL)
541 	    ys_free(ys);
542     }
543     if (yspec->ys_stmt)
544 	free(yspec->ys_stmt);
545     free(yspec);
546     return 0;
547 }
548 
549 /*! Allocate larger yang statement vector adding empty field last */
550 static int
yn_realloc(yang_stmt * yn)551 yn_realloc(yang_stmt *yn)
552 {
553     yn->ys_len++;
554 
555     if ((yn->ys_stmt = realloc(yn->ys_stmt, (yn->ys_len)*sizeof(yang_stmt *))) == 0){
556 	clicon_err(OE_YANG, errno, "realloc");
557 	return -1;
558     }
559     yn->ys_stmt[yn->ys_len - 1] = NULL; /* init field */
560     return 0;
561 }
562 
563 /*! Copy yang statement recursively from old to new
564  * @param[in] ynew  New empty (but created) yang statement (to)
565  * @param[in] yold  Old existing yang statement (from)
566  * @retval    0     OK
567  * @retval    -1    Error
568  * @code
569  * yang_stmt *new = ys_new(Y_LEAF);
570  * if (ys_cp(new, old) < 0)
571  *    err;
572  * @endcode
573  * @see ys_replace
574  */
575 int
ys_cp(yang_stmt * ynew,yang_stmt * yold)576 ys_cp(yang_stmt *ynew,
577       yang_stmt *yold)
578 {
579     int        retval = -1;
580     int        i;
581     yang_stmt *ycn; /* new child */
582     yang_stmt *yco; /* old child */
583 
584     memcpy(ynew, yold, sizeof(*yold));
585     ynew->ys_parent = NULL;
586     if (yold->ys_stmt)
587 	if ((ynew->ys_stmt = calloc(yold->ys_len, sizeof(yang_stmt *))) == NULL){
588 	    clicon_err(OE_YANG, errno, "calloc");
589 	    goto done;
590 	}
591     if (yold->ys_argument)
592 	if ((ynew->ys_argument = strdup(yold->ys_argument)) == NULL){
593 	    clicon_err(OE_YANG, errno, "strdup");
594 	    goto done;
595 	}
596     if (yold->ys_cv)
597 	if ((ynew->ys_cv = cv_dup(yold->ys_cv)) == NULL){
598 	    clicon_err(OE_YANG, errno, "cv_dup");
599 	    goto done;
600 	}
601     if (yold->ys_cvec)
602 	if ((ynew->ys_cvec = cvec_dup(yold->ys_cvec)) == NULL){
603 	    clicon_err(OE_YANG, errno, "cvec_dup");
604 	    goto done;
605 	}
606     if (yold->ys_typecache){
607 	ynew->ys_typecache = NULL;
608 	if (yang_type_cache_cp(ynew, yold) < 0)
609 	    goto done;
610     }
611     if (yold->ys_when_xpath)
612 	if ((ynew->ys_when_xpath = strdup(yold->ys_when_xpath)) == NULL){
613 	    clicon_err(OE_YANG, errno, "strdup");
614 	    goto done;
615 	}
616     if (yold->ys_when_nsc){
617 	if ((ynew->ys_when_nsc = cvec_dup(yold->ys_when_nsc)) == NULL){
618 	    clicon_err(OE_YANG, errno, "cvec_dup");
619 	    goto done;
620 	}
621     }
622     for (i=0; i<ynew->ys_len; i++){
623 	yco = yold->ys_stmt[i];
624 	if ((ycn = ys_dup(yco)) == NULL)
625 	    goto done;
626 	ynew->ys_stmt[i] = ycn;
627 	ycn->ys_parent = ynew;
628     }
629     retval = 0;
630  done:
631     return retval;
632 }
633 
634 /*! Create a new yang node and copy the contents recursively from the original.  *
635  * @param[in] old  Old existing yang statement (from)
636  * @retval    NULL Error
637  * @retval    nw   New created yang statement
638  * @retval    0     OK
639  * @retval    -1    Error
640  * This may involve duplicating strings, etc.
641  * The new yang tree needs to be freed by ys_free().
642  * The parent of new is NULL, it needs to be explicityl inserted somewhere
643  */
644 yang_stmt *
ys_dup(yang_stmt * old)645 ys_dup(yang_stmt *old)
646 {
647     yang_stmt *nw;
648 
649     if ((nw = ys_new(old->ys_keyword)) == NULL)
650 	return NULL;
651     if (nw->ys_cvec){
652 	cvec_free(nw->ys_cvec);
653 	nw->ys_cvec = NULL;
654     }
655     if (ys_cp(nw, old) < 0){
656 	ys_free(nw);
657 	return NULL;
658     }
659     return nw;
660 }
661 
662 /*! Replace yold with ynew (insert ynew at the exact place of yold). Keep yold pointer as-is.
663  *
664  * @param[in] yorig  Existing yang statement
665  * @param[in] yfrom   New empty (but created) yang statement
666 
667  * @retval    0     OK
668  * @retval    -1    Error
669  * @code
670  * if (ys_replace(new, old) < 0)
671  *    err;
672  * @endcode
673  * @see ys_cp
674  * @note yfrom is left in its original state
675  */
676 int
ys_replace(yang_stmt * yorig,yang_stmt * yfrom)677 ys_replace(yang_stmt *yorig,
678 	   yang_stmt *yfrom)
679 {
680     int        retval = -1;
681     yang_stmt *yp; /* parent */
682     yang_stmt *yc; /* child */
683 
684     yp = yang_parent_get(yorig);
685     /* Remove old yangs all children */
686     yc = NULL;
687     while ((yc = yn_each(yorig, yc)) != NULL)
688 	ys_free(yc);
689     if (yorig->ys_stmt){
690 	free(yorig->ys_stmt);
691 	yorig->ys_stmt = NULL;
692 	yorig->ys_len = 0;
693     }
694     ys_free1(yorig, 0); /* Remove all in yold except the actual object */
695     if (ys_cp(yorig, yfrom) < 0)
696 	goto done;
697     yorig->ys_parent = yp;
698     retval = 0;
699  done:
700     return retval;
701 }
702 
703 /*! Append yang statement as child of a parent yang_statement, last in list
704  *
705  * @param[in] ys_parent  Add child to this parent
706  * @param[in] ys_child   Add this child
707  * @retval    0          OK
708  * @retval   -1          Error
709  * Also add parent to child as up-pointer
710  * @see ys_prune
711  */
712 int
yn_insert(yang_stmt * ys_parent,yang_stmt * ys_child)713 yn_insert(yang_stmt *ys_parent,
714 	  yang_stmt *ys_child)
715 {
716     int pos = ys_parent->ys_len;
717 
718     if (yn_realloc(ys_parent) < 0)
719 	return -1;
720     ys_parent->ys_stmt[pos] = ys_child;
721     ys_child->ys_parent = ys_parent;
722     return 0;
723 }
724 
725 /*! Iterate through all yang statements from a yang node
726  *
727  * @param[in] yparent  yang statement whose children should be iterated
728  * @param[in] yprev    previous child, or NULL on init
729  * @code
730  *   yang_stmt *yprev = NULL;
731  *   while ((yprev = yn_each(yparent, yprev)) != NULL) {
732  *     ...yprev...
733  *   }
734  * @endcode
735  * @note makes uses _ys_vector_i:can be changed if list changed between calls
736  * @note also does not work in recursive calls (to same node)
737  */
738 yang_stmt *
yn_each(yang_stmt * yparent,yang_stmt * yprev)739 yn_each(yang_stmt *yparent,
740 	yang_stmt *yprev)
741 {
742     int        i;
743     yang_stmt *yc = NULL;
744 
745     if (yparent == NULL)
746 	return NULL;
747     for (i=yprev?yprev->_ys_vector_i+1:0; i<yparent->ys_len; i++){
748 	if ((yc = yparent->ys_stmt[i]) == NULL){
749 	    assert(yc); /* XXX Check if happens */
750 	    continue;
751 	}
752 	/* make room for other conditionals */
753 	break; /* this is next object after previous */
754     }
755     if (i < yparent->ys_len) /* found */
756 	yc->_ys_vector_i = i;
757     else
758 	yc = NULL;
759     return yc;
760 }
761 
762 /*! Find first child yang_stmt with matching keyword and argument
763  *
764  * @param[in]  yn         Yang node, current context node.
765  * @param[in]  keyword    if 0 match any keyword
766  * @param[in]  argument   String compare w argument. if NULL, match any.
767  * @retval     ys         Yang statement, if any
768  * This however means that if you actually want to match only a yang-stmt with
769  * argument==NULL you cannot, but I have not seen any such examples.
770  * @see yang_find_datanode
771  * @see yang_match  returns number of matches
772  */
773 yang_stmt *
yang_find(yang_stmt * yn,int keyword,const char * argument)774 yang_find(yang_stmt  *yn,
775 	  int         keyword,
776 	  const char *argument)
777 {
778     yang_stmt *ys = NULL;
779     int        i;
780     yang_stmt *yret = NULL;
781     char      *name;
782     yang_stmt *yspec;
783     yang_stmt *ym;
784 
785     for (i=0; i<yn->ys_len; i++){
786 	ys = yn->ys_stmt[i];
787 	if (keyword == 0 || ys->ys_keyword == keyword){
788 	    if (argument == NULL ||
789 		(ys->ys_argument && strcmp(argument, ys->ys_argument) == 0)){
790 		yret = ys;
791 		break;
792 	    }
793 	}
794     }
795     /* Special case: if not match and yang node is module or submodule, extend
796      * search to include submodules */
797     if (yret == NULL &&
798 	(yang_keyword_get(yn) == Y_MODULE ||
799 	 yang_keyword_get(yn) == Y_SUBMODULE)){
800 	yspec = ys_spec(yn);
801 	for (i=0; i<yn->ys_len; i++){
802 	    ys = yn->ys_stmt[i];
803 	    if (yang_keyword_get(ys) == Y_INCLUDE){
804 		name = yang_argument_get(ys);
805 		if ((ym = yang_find_module_by_name(yspec, name)) != NULL &&
806 		    (yret = yang_find(ym, keyword, argument)) != NULL)
807 		    break;
808 	    }
809 	}
810     }
811     return yret;
812 }
813 
814 /*! Count number of children that matches keyword and argument
815  *
816  * @param[in]  yn         Yang node, current context node.
817  * @param[in]  keyword    if 0 match any keyword
818  * @param[in]  argument   String compare w argument. if NULL, match any.
819  * @retval     n          Number of matches
820  * This however means that if you actually want to match only a yang-stmt with
821  * argument==NULL you cannot, but I have not seen any such examples.
822  * @see yang_find
823  */
824 int
yang_match(yang_stmt * yn,int keyword,char * argument)825 yang_match(yang_stmt *yn,
826 	   int        keyword,
827 	   char      *argument)
828 {
829     yang_stmt *ys = NULL;
830     int        i;
831     int        match = 0;
832 
833     for (i=0; i<yn->ys_len; i++){
834 	ys = yn->ys_stmt[i];
835 	if (keyword == 0 || ys->ys_keyword == keyword){
836 	    if (argument == NULL)
837 		match++;
838 	    else
839 		if (ys->ys_argument && strcmp(argument, ys->ys_argument) == 0)
840 		    match++;
841 	}
842     }
843     return match;
844 }
845 
846 /*! Find child data node with matching argument (container, leaf, list, leaf-list)
847  *
848  * @param[in]  yn         Yang node, current context node.
849  * @param[in]  argument   if NULL, match any(first) argument. XXX is that really a case?
850  *
851  * @see yang_find   Looks for any node
852  * @note May deviate from RFC since it explores choice/case not just return it.
853  */
854 yang_stmt *
yang_find_datanode(yang_stmt * yn,char * argument)855 yang_find_datanode(yang_stmt *yn,
856 		   char      *argument)
857 {
858     yang_stmt *ys = NULL;
859     yang_stmt *yc = NULL;
860     yang_stmt *yspec;
861     yang_stmt *ysmatch = NULL;
862     char      *name;
863 
864     ys = NULL;
865     while ((ys = yn_each(yn, ys)) != NULL){
866 	if (yang_keyword_get(ys) == Y_CHOICE){ /* Look for its children */
867 	    yc = NULL;
868 	    while ((yc = yn_each(ys, yc)) != NULL){
869 		if (yang_keyword_get(yc) == Y_CASE) /* Look for its children */
870 		    ysmatch = yang_find_datanode(yc, argument);
871 		else
872 		    if (yang_datanode(yc)){
873 			if (argument == NULL)
874 			    ysmatch = yc;
875 			else
876 			    if (yc->ys_argument && strcmp(argument, yc->ys_argument) == 0)
877 				ysmatch = yc;
878 		    }
879 		if (ysmatch)
880 		    goto match;
881 	    }
882 	} /* Y_CHOICE */
883 	else{
884 	    if (yang_datanode(ys)){
885 		if (argument == NULL)
886 		    ysmatch = ys;
887 		else
888 		    if (ys->ys_argument && strcmp(argument, ys->ys_argument) == 0)
889 			ysmatch = ys;
890 		if (ysmatch)
891 		    goto match;
892 	    }
893 	}
894     }
895     /* Special case: if not match and yang node is module or submodule, extend
896      * search to include submodules */
897     if (ysmatch == NULL &&
898 	(yang_keyword_get(yn) == Y_MODULE ||
899 	 yang_keyword_get(yn) == Y_SUBMODULE)){
900 	yspec = ys_spec(yn);
901 	ys = NULL;
902 	while ((ys = yn_each(yn, ys)) != NULL){
903 	    if (yang_keyword_get(ys) == Y_INCLUDE){
904 		name = yang_argument_get(ys);
905 		yc = yang_find_module_by_name(yspec, name);
906 		if ((ysmatch = yang_find_datanode(yc, argument)) != NULL)
907 		    break;
908 	    }
909 	}
910     }
911  match:
912     return ysmatch;
913 }
914 
915 /*! Find child schema node with matching argument (container, leaf, etc)
916  * @param[in]  yn         Yang node, current context node.
917  * @param[in]  argument   if NULL, match any(first) argument.
918  * @note XXX unify code with yang_find_datanode?
919  * @see yang_find_datanode
920  */
921 yang_stmt *
yang_find_schemanode(yang_stmt * yn,char * argument)922 yang_find_schemanode(yang_stmt *yn,
923 		     char      *argument)
924 {
925     yang_stmt *ys = NULL;
926     yang_stmt *yc = NULL;
927     yang_stmt *yspec;
928     yang_stmt *ysmatch = NULL;
929     char      *name;
930     int        i, j;
931 
932     for (i=0; i<yn->ys_len; i++){
933 	ys = yn->ys_stmt[i];
934 	if (ys->ys_keyword == Y_CHOICE){ /* Look for its children */
935 	    for (j=0; j<ys->ys_len; j++){
936 		yc = ys->ys_stmt[j];
937 		if (yc->ys_keyword == Y_CASE) /* Look for its children */
938 		    ysmatch = yang_find_schemanode(yc, argument);
939 		else
940 		    if (yang_schemanode(yc)){
941 			if (argument == NULL)
942 			    ysmatch = yc;
943 			else
944 			    if (yc->ys_argument && strcmp(argument, yc->ys_argument) == 0)
945 				ysmatch = yc;
946 		    }
947 		if (ysmatch)
948 		    goto match;
949 	    }
950 	} /* Y_CHOICE */
951 	else
952 	    if (yang_schemanode(ys)){
953 		if (argument == NULL)
954 		    ysmatch = ys;
955 		else
956 		    if (ys->ys_argument && strcmp(argument, ys->ys_argument) == 0)
957 			ysmatch = ys;
958 		if (ysmatch)
959 		    goto match;
960 	    }
961     }
962     /* Special case: if not match and yang node is module or submodule, extend
963      * search to include submodules */
964     if (ysmatch == NULL &&
965 	(yang_keyword_get(yn) == Y_MODULE ||
966 	 yang_keyword_get(yn) == Y_SUBMODULE)){
967 	yspec = ys_spec(yn);
968 	for (i=0; i<yn->ys_len; i++){
969 	    ys = yn->ys_stmt[i];
970 	    if (yang_keyword_get(ys) == Y_INCLUDE){
971 		name = yang_argument_get(ys);
972 		yc = yang_find_module_by_name(yspec, name);
973 		if ((ysmatch = yang_find_schemanode(yc, argument)) != NULL)
974 		    break;
975 	    }
976 	}
977     }
978  match:
979     return ysmatch;
980 }
981 
982 /*! Given a yang statement, find the prefix associated to this module
983  *
984  * @param[in]  ys        Yang statement in module tree (or module itself)
985  * @retval     NULL      No prefix found. This is an error
986  * @retval     prefix    OK: Prefix as char* pointer into yang tree
987  * @code
988  * char *myprefix;
989  * myprefix = yang_find_myprefix(ys);
990  * @endcode
991  */
992 char *
yang_find_myprefix(yang_stmt * ys)993 yang_find_myprefix(yang_stmt *ys)
994 {
995     yang_stmt *ymod = NULL; /* My module */
996     yang_stmt *yprefix;
997     char      *prefix = NULL;
998 
999     /* Not good enough with submodule, must be actual module */
1000     if (ys_real_module(ys, &ymod) < 0)
1001 	goto done;
1002     if (ymod == NULL){
1003 	clicon_err(OE_YANG, ENOENT, "Internal error: no module");
1004 	goto done;
1005     }
1006     if ((yprefix = yang_find(ymod, Y_PREFIX, NULL)) == NULL){
1007 	clicon_err(OE_YANG, ENOENT, "No prefix found for module %s", yang_argument_get(ymod));
1008 	goto done;
1009     }
1010     prefix = yang_argument_get(yprefix);
1011  done:
1012     return prefix;
1013 }
1014 
1015 /*! Given a yang statement, find the namespace URI associated to this module
1016  *
1017  * @param[in]  ys        Yang statement in module tree (or module itself)
1018  * @retval     NULL      Error: No namespace found. This is an error
1019  * @retval     ns        Namspace URI as char* pointer into yang tree
1020  * @code
1021  * char *myns = yang_find_mynamespace(ys);
1022  * @endcode
1023  * @see yang_find_module_by_namespace
1024  */
1025 char *
yang_find_mynamespace(yang_stmt * ys)1026 yang_find_mynamespace(yang_stmt *ys)
1027 {
1028     yang_stmt *ymod = NULL; /* My module */
1029     yang_stmt *ynamespace;
1030     char      *ns = NULL;
1031 
1032     if (ys_real_module(ys, &ymod) < 0)
1033 	goto done;
1034     if ((ynamespace = yang_find(ymod, Y_NAMESPACE, NULL)) == NULL){
1035 	clicon_err(OE_YANG, ENOENT, "No namespace found for module %s", yang_argument_get(ymod));
1036 	goto done;
1037     }
1038     ns = yang_argument_get(ynamespace);
1039  done:
1040     return ns;
1041 }
1042 
1043 /*! Given a yang statement and namespace, find local prefix valid in module
1044  * This is useful if you want to make a "reverse" lookup, you know the
1045  * (global) namespace of a module, but you do not know the local prefix
1046  * used to access it in XML.
1047  * @param[in]  ys        Yang statement in module tree (or module itself)
1048  * @param[in]  ns		 Namspace URI as char* pointer into yang tree
1049  * @param[out] prefix    Local prefix to access module with (direct pointer)
1050  * @retval     0         not found
1051  * @retval    -1         found
1052  * @note  prefix NULL is not returned, if own module, then return its prefix
1053  * @code
1054  *    char *prefix = NULL;
1055  *    if (yang_find_prefix_by_namespace(ys, "urn:example:clixon", &prefix) < 0)
1056  *      err;
1057  * @endcode
1058  */
1059 int
yang_find_prefix_by_namespace(yang_stmt * ys,char * ns,char ** prefix)1060 yang_find_prefix_by_namespace(yang_stmt *ys,
1061 			      char      *ns,
1062 			      char     **prefix)
1063 {
1064     int        retval = 0; /* not found */
1065     yang_stmt *my_ymod; /* My module */
1066     char      *myns;   /* My ns */
1067     yang_stmt *yspec;
1068     yang_stmt *ymod;
1069     char      *modname = NULL;
1070     yang_stmt *yimport;
1071     yang_stmt *yprefix;
1072 
1073     clicon_debug(1, "%s", __FUNCTION__);
1074     /* First check if namespace is my own module */
1075     myns = yang_find_mynamespace(ys);
1076     if (strcmp(myns, ns) == 0){
1077 	*prefix = yang_find_myprefix(ys); /* or NULL? */
1078 	goto found;
1079     }
1080     /* Next, find namespaces in imported modules */
1081     yspec = ys_spec(ys);
1082     if ((ymod = yang_find_module_by_namespace(yspec, ns)) == NULL)
1083 	goto notfound;
1084     modname = yang_argument_get(ymod);
1085     my_ymod = ys_module(ys);
1086     /* Loop through import statements to find a match with ymod */
1087     yimport = NULL;
1088     while ((yimport = yn_each(my_ymod, yimport)) != NULL) {
1089 	if (yang_keyword_get(yimport) == Y_IMPORT &&
1090 	    strcmp(modname, yang_argument_get(yimport)) == 0){ /* match */
1091 	    yprefix = yang_find(yimport, Y_PREFIX, NULL);
1092 	    *prefix = yang_argument_get(yprefix);
1093 	    goto found;
1094 	}
1095     }
1096  notfound:
1097     return retval;
1098  found:
1099     assert(*prefix);
1100     return 1;
1101 }
1102 
1103 /*! Return topmost yang root node directly under module/submodule
1104  *
1105  * @param[in] ys    Yang statement
1106  * @retval    ytop  Topmost yang node (can be ys itself)
1107  * @retval    NULL  ys is spec, module, NULL etc with no reasonable rootnode
1108  */
1109 yang_stmt *
yang_myroot(yang_stmt * ys)1110 yang_myroot(yang_stmt *ys)
1111 {
1112     yang_stmt    *yp;
1113     enum rfc_6020 kw;
1114 
1115     kw = yang_keyword_get(ys);
1116     if (ys==NULL || kw==Y_SPEC || kw == Y_MODULE || kw == Y_SUBMODULE)
1117 	return NULL;
1118     yp = yang_parent_get(ys);
1119     while((yp = yang_parent_get(ys)) != NULL) {
1120 	kw = yang_keyword_get(yp);
1121 	if (kw == Y_MODULE || kw == Y_SUBMODULE)
1122 	    return ys;
1123 	ys = yp;
1124     }
1125     return NULL;
1126 }
1127 
1128 /*! If a given yang stmt has a choice/case as parent, return the choice statement
1129  */
1130 yang_stmt *
yang_choice(yang_stmt * y)1131 yang_choice(yang_stmt *y)
1132 {
1133     yang_stmt *yp;
1134 
1135     if ((yp = y->ys_parent) != NULL){
1136 	switch (yang_keyword_get(yp)){
1137 	case Y_CHOICE:
1138 	    return yp;
1139 	    break;
1140 	case Y_CASE:
1141 	    return yang_parent_get(yp);
1142 	    break;
1143 	default:
1144 	    break;
1145 	}
1146     }
1147     return NULL;
1148 }
1149 
1150 /*! Find matching y in yp:s children, "yang order" of y when y is choice
1151  * @param[in]  yp     Choice node
1152  * @param[in]  y      Yang datanode to find
1153  * @param[out] index  Index of y in yp:s list of children
1154  * @retval     0      not found (must be datanode)
1155  * @retval     1      found
1156  * @see order1 the main function
1157  * There are two distinct cases, either (1) the choice has case statements, or
1158  * (2) it uses shortcut mode without case statements.
1159  * In (1) we need to count how many sub-statements and keep a max
1160  * In (2) we increment with only 1.
1161  */
1162 static int
order1_choice(yang_stmt * yp,yang_stmt * y,int * index)1163 order1_choice(yang_stmt *yp,
1164 	      yang_stmt *y,
1165 	      int       *index)
1166 {
1167     yang_stmt  *ys;
1168     yang_stmt  *yc;
1169     int         i;
1170     int         j;
1171     int         shortcut=0;
1172     int         max=0;
1173 
1174     for (i=0; i<yp->ys_len; i++){ /* Loop through choice */
1175 	ys = yp->ys_stmt[i];
1176 	if (ys->ys_keyword == Y_CASE){ /* Loop through case */
1177 	    for (j=0; j<ys->ys_len; j++){
1178 		yc = ys->ys_stmt[j];
1179 		if (yang_datanode(yc) && yc == y){
1180 		    *index += j;
1181 		    return 1;
1182 		}
1183 	    }
1184 	    if (j>max)
1185 		max = j;
1186 	}
1187 	else {
1188 	    shortcut = 1;   /* Shortcut, no case */
1189 	    if (yang_datanode(ys) && ys == y)
1190 		return 1;
1191 	}
1192     }
1193     if (shortcut)
1194 	(*index)++;
1195     else
1196 	*index += max;
1197     return 0;
1198 }
1199 
1200 /*! Find matching y in yp:s children, return "yang order" of y or -1 if not found
1201  * @param[in]  yp     Parent
1202  * @param[in]  y      Yang datanode to find
1203  * @param[out] index  Index of y in yp:s list of children
1204  * @retval     0      not found (must be datanode)
1205  * @retval     1      found
1206  */
1207 static int
order1(yang_stmt * yp,yang_stmt * y,int * index)1208 order1(yang_stmt *yp,
1209        yang_stmt *y,
1210        int       *index)
1211 {
1212     yang_stmt  *ys;
1213     int         i;
1214 
1215     for (i=0; i<yp->ys_len; i++){
1216 	ys = yp->ys_stmt[i];
1217 	if (ys->ys_keyword == Y_CHOICE){
1218 	    if (order1_choice(ys, y, index) == 1) /* If one of the choices is "y" */
1219 		return 1;
1220 	}
1221 	else {
1222 	    if (!yang_datanode(ys))
1223 		continue;
1224 	    if (ys==y)
1225 		return 1;
1226 	    (*index)++;
1227 	}
1228     }
1229     return 0;
1230 }
1231 
1232 /*! Return order of yang statement y in parents child vector
1233  * @param[in]  y      Find position of this data-node
1234  * @param[out] index  Index of y in yp:s list of children
1235  * @retval   >=0      Order of child with specified argument
1236  * @retval    -1      Not found
1237  * @note special handling if y is child of (sub)module
1238  */
1239 int
yang_order(yang_stmt * y)1240 yang_order(yang_stmt *y)
1241 {
1242     yang_stmt  *yp;
1243     yang_stmt  *ypp;
1244     yang_stmt  *ym;
1245     int         i;
1246     int         j=0;
1247     int         tot = 0;
1248 
1249     if (y == NULL)
1250 	return -1;
1251     /* Some special handling if yp is choice (or case)
1252      * if so, the real parent (from an xml point of view) is the parents
1253      * parent.
1254      */
1255     yp = yang_parent_get(y);
1256     while (yang_keyword_get(yp) == Y_CASE || yang_keyword_get(yp) == Y_CHOICE)
1257 	yp = yp->ys_parent;
1258 
1259     /* XML nodes with yang specs that are children of modules are special -
1260      * In clixon, they are seen as an "implicit" container where the XML can come from different
1261      * modules. The order must therefore be global among yang top-symbols to be unique.
1262      * Example: <x xmlns="foo"/><y xmlns="bar"/>
1263      * The order of x and y cannot be compared within a single yang module since they belong to different
1264      */
1265     if (yang_keyword_get(yp) == Y_MODULE || yang_keyword_get(yp) == Y_SUBMODULE){
1266 	ypp = yang_parent_get(yp); /* yang spec */
1267 	for (i=0; i<ypp->ys_len; i++){ /* iterate through other modules */
1268 	    ym = ypp->ys_stmt[i];
1269 	    if (yp == ym)
1270 		break;
1271 	    tot += ym->ys_len;
1272 	}
1273     }
1274     if (order1(yp, y, &j) == 1)
1275 	return tot + j;
1276     return -1;
1277 }
1278 
1279 char *
yang_key2str(int keyword)1280 yang_key2str(int keyword)
1281 {
1282     return (char*)clicon_int2str(ykmap, keyword);
1283 }
1284 
1285 /*! Find top data node among all modules by namespace in xml tree
1286  * @param[in]  yspec    Yang specification
1287  * @param[in]  xt       XML node
1288  * @param[out] ymod     Yang module (NULL if not found)
1289  * @retval     0        OK
1290  * @retval    -1        Error
1291  * @note works for xml namespaces (xmlns / xmlns:ns)
1292  * Note that xt xml symbol may belong to submodule of ymod
1293  */
1294 int
ys_module_by_xml(yang_stmt * yspec,cxobj * xt,yang_stmt ** ymodp)1295 ys_module_by_xml(yang_stmt  *yspec,
1296 		 cxobj      *xt,
1297 		 yang_stmt **ymodp)
1298 {
1299     int        retval = -1;
1300     yang_stmt *ym = NULL; /* module */
1301     char      *prefix = NULL;
1302     char      *ns = NULL; /* namespace URI */
1303 
1304     if (ymodp)
1305 	*ymodp = NULL;
1306     prefix = xml_prefix(xt);
1307     if (xml2ns(xt, prefix, &ns) < 0) /* prefix may be NULL */
1308 	goto done;
1309     /* No namespace found, give up */
1310     if (ns == NULL)
1311 	goto ok;
1312     /* We got the namespace, now get the module */
1313     ym = yang_find_module_by_namespace(yspec, ns);
1314     /* Set result param */
1315     if (ymodp && ym)
1316 	*ymodp = ym;
1317  ok:
1318     retval = 0;
1319  done:
1320     return retval;
1321 }
1322 
1323 /*! Find the top module or sub-module given a statement from within a yang tree
1324  * Ultimate top is yang spec, dont return that
1325  * The routine recursively finds ancestors.
1326  * @param[in] ys    Any yang statement in a yang tree
1327  * @retval    ymod  The top module or sub-module
1328  * @see ys_spec
1329  * @see ys_real_module find the submodule's belongs-to module
1330  * @note For an augmented node, the original module is returned
1331  */
1332 yang_stmt *
ys_module(yang_stmt * ys)1333 ys_module(yang_stmt *ys)
1334 {
1335     yang_stmt *yn;
1336 
1337     if (ys==NULL || ys->ys_keyword==Y_SPEC)
1338 	return NULL;
1339     if (ys->ys_keyword == Y_MODULE || ys->ys_keyword == Y_SUBMODULE)
1340 	return ys;
1341     while (ys != NULL &&
1342 	   ys->ys_keyword != Y_MODULE &&
1343 	   ys->ys_keyword != Y_SUBMODULE){
1344 	if (ys->ys_mymodule){ /* shortcut due to augment */
1345 	    ys = ys->ys_mymodule;
1346 	    break;
1347 	}
1348 	yn = ys->ys_parent;
1349 	/* Some extra stuff to ensure ys is a stmt */
1350 	if (yn && yn->ys_keyword == Y_SPEC)
1351 	    yn = NULL;
1352 	ys = (yang_stmt*)yn;
1353     }
1354     /* Here it is either NULL or is a typedef-kind yang-stmt */
1355     return ys;
1356 }
1357 
1358 /*! Find real top module given a statement in a yang tree
1359  * With "real" top module means that if sub-module is the top-node,
1360  * the module that the sub-module belongs-to is found recursively
1361  * @param[in]  ys    Any yang statement in a yang tree
1362  * @param[out] ymod  The top module or sub-module
1363  * @retval     0     OK, returned module in ymod
1364  * @retval    -1     YANG validation error: all yang statements should have a "real" module
1365  * @see ys_module
1366  * @note For an augmented node, the original module is returned
1367  */
1368 int
ys_real_module(yang_stmt * ys,yang_stmt ** ymod)1369 ys_real_module(yang_stmt  *ys,
1370 	       yang_stmt **ymod)
1371 {
1372     int        retval = -1;
1373     yang_stmt *ym = NULL;
1374     yang_stmt *yb;
1375     char      *name;
1376     yang_stmt *yspec;
1377 
1378     if (ymod == NULL){
1379 	clicon_err(OE_YANG, EINVAL, "ymod is NULL");
1380 	goto done;
1381     }
1382     if ((ym = ys_module(ys)) != NULL){
1383 	yspec = ys_spec(ym);
1384 	while (ym && yang_keyword_get(ym) == Y_SUBMODULE){
1385 	    if ((yb = yang_find(ym, Y_BELONGS_TO, NULL)) == NULL){
1386 		clicon_err(OE_YANG, ENOENT, "No belongs-to statement of submodule %s", yang_argument_get(ym)); /* shouldnt happen */
1387 		goto done;
1388 	    }
1389 	    if ((name = yang_argument_get(yb)) == NULL){
1390 		clicon_err(OE_YANG, ENOENT, "Belongs-to statement of submodule %s has no argument", yang_argument_get(ym)); /* shouldnt happen */
1391 		goto done;
1392 	    }
1393 	    if ((ym = yang_find_module_by_name(yspec, name)) == NULL)
1394 		goto done;
1395 	}
1396     }
1397     *ymod = ym;
1398     retval = 0;
1399  done:
1400     return retval;
1401 }
1402 
1403 /*! Find top of tree, the yang specification from within the tree
1404  * @param[in] ys    Any yang statement in a yang tree
1405  * @retval    yspec The top yang specification
1406  * @see  ys_module
1407  * @see  yang_augment_node where shortcut is set
1408  */
1409 yang_stmt *
ys_spec(yang_stmt * ys)1410 ys_spec(yang_stmt *ys)
1411 {
1412     yang_stmt *yn;
1413 
1414     while (ys != NULL && ys->ys_keyword != Y_SPEC){
1415 	yn = ys->ys_parent;
1416 	ys = (yang_stmt*)yn;
1417     }
1418     /* Here it is either NULL or is a typedef-kind yang-stmt */
1419     return (yang_stmt*)ys;
1420 }
1421 
1422 /*! string is quoted if it contains space or tab, needs double '' */
1423 static int inline
quotedstring(char * s)1424 quotedstring(char *s)
1425 {
1426     int len = strlen(s);
1427     int i;
1428 
1429     for (i=0; i<len; i++)
1430 	if (isblank(s[i]))
1431 	    break;
1432     return i < len;
1433 }
1434 
1435 /*! Print yang specification to file
1436  * @param[in]  f     File to print to.
1437  * @param[in]  yn    Yang node to print
1438  * @param[in]  fn    Callback to make print function
1439  * @see yang_print_cbuf
1440  */
1441 int
yang_print_cb(FILE * f,yang_stmt * yn,clicon_output_cb * fn)1442 yang_print_cb(FILE             *f,
1443 	      yang_stmt        *yn,
1444 	      clicon_output_cb *fn)
1445 {
1446     int        retval = -1;
1447     cbuf      *cb = NULL;
1448 
1449     if ((cb = cbuf_new()) == NULL){
1450 	clicon_err(OE_YANG, errno, "cbuf_new");
1451 	goto done;
1452     }
1453     if (yang_print_cbuf(cb, yn, 0) < 0)
1454 	goto done;
1455     (*fn)(f, "%s", cbuf_get(cb));
1456     if (cb)
1457 	cbuf_free(cb);
1458     retval = 0;
1459  done:
1460     return retval;
1461 }
1462 
1463 /*! Print yang specification to file
1464  * @param[in]  f         File to print to.
1465  * @param[in]  yn        Yang node to print
1466  * @see yang_print_cbuf
1467  */
1468 int
yang_print(FILE * f,yang_stmt * yn)1469 yang_print(FILE      *f,
1470 	   yang_stmt *yn)
1471 {
1472     return yang_print_cb(f, yn, fprintf);
1473 }
1474 
1475 /*! Print yang specification to cligen buf
1476  * @param[in]  cb        Cligen buffer. This is where the pretty print is.
1477  * @param[in]  yn        Yang node to print
1478  * @param[in]  marginal  Tab indentation, mainly for recursion.
1479  * @code
1480  *  cbuf *cb = cbuf_new();
1481  *  yang_print_cbuf(cb, yn, 0);
1482  *  // output is in cbuf_buf(cb);
1483  *  cbuf_free(cb);
1484  * @endcode
1485  */
1486 int
yang_print_cbuf(cbuf * cb,yang_stmt * yn,int marginal)1487 yang_print_cbuf(cbuf      *cb,
1488 		yang_stmt *yn,
1489 		int        marginal)
1490 {
1491     yang_stmt *ys = NULL;
1492 
1493     while ((ys = yn_each(yn, ys)) != NULL) {
1494 	if (ys->ys_keyword == Y_UNKNOWN){ /* dont print unknown - proxy for extension*/
1495 	    cprintf(cb, "%*s", marginal-1, "");
1496 	}
1497 	else
1498 	    cprintf(cb, "%*s%s", marginal, "", yang_key2str(ys->ys_keyword));
1499 	if (ys->ys_argument){
1500 	    if (quotedstring(ys->ys_argument))
1501 		cprintf(cb, " \"%s\"", ys->ys_argument);
1502 	    else
1503 		cprintf(cb, " %s", ys->ys_argument);
1504 	}
1505 	if (ys->ys_len){
1506 	    cprintf(cb, " {\n");
1507 	    yang_print_cbuf(cb, ys, marginal+3);
1508 	    cprintf(cb, "%*s%s\n", marginal, "", "}");
1509 	}
1510 	else
1511 	    cprintf(cb, ";\n");
1512     }
1513     return 0;
1514 }
1515 
1516 /*! Populate yang leafs after parsing. Create cv and fill it in.
1517  *
1518  * Populate leaf in 2nd round of yang parsing, now that context is complete:
1519  * 1. Find type specification and set cv type accordingly
1520  * 2. Create the CV using cvtype and name it
1521  * 3. Check if default value. Here we parse the string in the default-stmt and add it to leafs cv.
1522  * 4. Check if leaf is part of list, if key exists mark leaf as key/unique
1523  * XXX: extend type search
1524  *
1525  * @param[in] h    Clicon handle
1526  * @param[in] ys   The yang statement to populate.
1527  * @retval    0    OK
1528  * @retval    -1   Error with clicon_err called
1529  */
1530 static int
ys_populate_leaf(clicon_handle h,yang_stmt * ys)1531 ys_populate_leaf(clicon_handle h,
1532 		 yang_stmt *ys)
1533 {
1534     int             retval = -1;
1535     cg_var         *cv = NULL;
1536     yang_stmt      *yparent;
1537     yang_stmt      *ydef;
1538     enum cv_type    cvtype = CGV_ERR;
1539     int             cvret;
1540     int             ret;
1541     char           *reason = NULL;
1542     yang_stmt      *yrestype;  /* resolved type */
1543     char           *restype;  /* resolved type */
1544     char           *origtype=NULL;   /* original type */
1545     uint8_t         fraction_digits;
1546     int             options = 0x0;
1547     yang_stmt      *ytypedef; /* where type is define */
1548 
1549     yparent = ys->ys_parent;     /* Find parent: list/container */
1550     /* 1. Find type specification and set cv type accordingly */
1551     if (yang_type_get(ys, &origtype, &yrestype, &options, NULL, NULL, NULL, &fraction_digits)
1552  < 0)
1553 	goto done;
1554     restype = yrestype?yrestype->ys_argument:NULL;
1555     if (clicon_type2cv(origtype, restype, ys, &cvtype) < 0) /* This handles non-resolved also */
1556 	goto done;
1557     /* 2. Create the CV using cvtype and name it */
1558     if ((cv = cv_new(cvtype)) == NULL){
1559 	clicon_err(OE_YANG, errno, "cv_new");
1560 	goto done;
1561     }
1562     if (options & YANG_OPTIONS_FRACTION_DIGITS && cvtype == CGV_DEC64) /* XXX: Seems misplaced? / too specific */
1563 	cv_dec64_n_set(cv, fraction_digits);
1564 
1565     if (cv_name_set(cv, ys->ys_argument) == NULL){
1566 	clicon_err(OE_YANG, errno, "cv_new_set");
1567 	goto done;
1568     }
1569     /* get parent of where type is defined, can be original object */
1570     ytypedef = yrestype?yang_parent_get(yrestype):ys;
1571 
1572     /* 3. Check if default value. Here we parse the string in the default-stmt
1573      * and add it to the leafs cv.
1574      * 3a) First check local default
1575      */
1576     if ((ydef = yang_find(ys, Y_DEFAULT, NULL)) != NULL){
1577 	if ((cvret = cv_parse1(ydef->ys_argument, cv, &reason)) < 0){ /* error */
1578 	    clicon_err(OE_YANG, errno, "parsing cv");
1579 	    goto done;
1580 	}
1581 	if (cvret == 0){ /* parsing failed */
1582 	    clicon_err(OE_YANG, errno, "Parsing CV: %s", reason);
1583 	    free(reason);
1584 	    goto done;
1585 	}
1586     }
1587     /* 2. then check typedef default */
1588     else if (ytypedef != ys &&
1589 	     (ydef = yang_find(ytypedef, Y_DEFAULT, NULL)) != NULL) {
1590 	if ((cvret = cv_parse1(ydef->ys_argument, cv, &reason)) < 0){ /* error */
1591 	    clicon_err(OE_YANG, errno, "parsing cv");
1592 	    goto done;
1593 	}
1594 	if (cvret == 0){ /* parsing failed */
1595 	    clicon_err(OE_YANG, errno, "Parsing CV: %s", reason);
1596 	    free(reason);
1597 	    goto done;
1598 	}
1599     }
1600     else{
1601 	/* 3b. If not default value, indicate empty cv. */
1602 	cv_flag_set(cv, V_UNSET); /* no value (no default) */
1603     }
1604     /* 4. Check if leaf is part of list, if key exists mark leaf as key/unique */
1605     if (yparent && yparent->ys_keyword == Y_LIST){
1606 	if ((ret = yang_key_match(yparent, ys->ys_argument)) < 0)
1607 	    goto done;
1608     }
1609     ys->ys_cv = cv;
1610     retval = 0;
1611   done:
1612     if (origtype)
1613 	free(origtype);
1614     if (cv && retval < 0)
1615 	cv_free(cv);
1616     return retval;
1617 }
1618 
1619 /*! Populate list yang statement
1620  * @param[in] h    Clicon handle
1621  * @param[in] ys   The yang statement (type) to populate.
1622  */
1623 static int
ys_populate_list(clicon_handle h,yang_stmt * ys)1624 ys_populate_list(clicon_handle h,
1625 		 yang_stmt    *ys)
1626 {
1627     yang_stmt  *ykey;
1628 
1629     if ((ykey = yang_find(ys, Y_KEY, NULL)) == NULL)
1630 	return 0;
1631     if (ys->ys_cvec)
1632 	cvec_free(ys->ys_cvec);
1633     if ((ys->ys_cvec = yang_arg2cvec(ykey, " ")) == NULL)
1634 	return -1;
1635     return 0;
1636 }
1637 
1638 /*! Set range or length boundary for built-in yang types
1639  * Help functions to range and length statements
1640  */
1641 static int
bound_add(yang_stmt * ys,enum cv_type cvtype,char * name,char * val,uint8_t fraction_digits)1642 bound_add(yang_stmt   *ys,
1643 	  enum cv_type cvtype,
1644 	  char        *name,
1645 	  char        *val,
1646 	  uint8_t      fraction_digits)
1647 {
1648     int     retval = -1;
1649     cg_var *cv;
1650     char   *reason = NULL;
1651     int     ret = 1;
1652 
1653     if ((cv = cvec_add(ys->ys_cvec, cvtype)) == NULL){
1654 	clicon_err(OE_YANG, errno, "cvec_add");
1655 	goto done;
1656     }
1657     if (cv_name_set(cv, name) == NULL){
1658 	clicon_err(OE_YANG, errno, "cv_name_set(%s)", name);
1659 	goto done;
1660     }
1661     if (cvtype == CGV_DEC64)
1662 	cv_dec64_n_set(cv, fraction_digits);
1663     if (strcmp(val, "min") == 0)
1664 	cv_min_set(cv);
1665     else if (strcmp(val, "max") == 0)
1666 	cv_max_set(cv);
1667     else if ((ret = cv_parse1(val, cv, &reason)) < 0){
1668 	clicon_err(OE_YANG, errno, "cv_parse1");
1669 	goto done;
1670     }
1671     if (ret == 0){ /* parsing failed */
1672 	clicon_err(OE_YANG, errno, "range statement %s: %s", val, reason);
1673 	free(reason);
1674 	goto done;
1675     }
1676     retval = 0;
1677  done:
1678     return retval;
1679 }
1680 
1681 /*! Common range length parsing of "x .. y | z..w " statements
1682  */
1683 static int
range_parse(yang_stmt * ys,enum cv_type cvtype,uint8_t fraction_digits)1684 range_parse(yang_stmt   *ys,
1685 	    enum cv_type cvtype,
1686 	    uint8_t      fraction_digits)
1687 {
1688     int    retval = -1;
1689     char **vec = NULL;
1690     int    nvec;
1691     int    i;
1692     char  *v;
1693     char  *v2;
1694 
1695     if ((vec = clicon_strsep(ys->ys_argument, "|", &nvec)) == NULL)
1696 	goto done;
1697     for (i=0; i<nvec; i++){
1698 	v = vec[i];
1699 	if ((v2 = strstr(v, "..")) != NULL){
1700 	    *v2 = '\0';
1701 	    v2 += 2;
1702 	    v2 = clixon_trim(v2); 	    /* trim blanks */
1703 	}
1704 	v = clixon_trim(v); 	/* trim blanks */
1705 	if (bound_add(ys, cvtype, "range_min", v, fraction_digits) < 0)
1706 	    goto done;
1707 	if (v2)
1708 	    if (bound_add(ys, cvtype, "range_max", v2, fraction_digits) < 0)
1709 		goto done;
1710     }
1711     retval = 0;
1712   done:
1713     if (vec)
1714 	free(vec);
1715     return retval;
1716 }
1717 
1718 /*! Populate string built-in range statement
1719  *
1720  * Create cvec variables "range_min" and "range_max". Assume parent is type.
1721  * @param[in] h    Clicon handle
1722  * @param[in] ys   The yang statement (range) to populate.
1723  * Actually: bound[..bound] (| bound[..bound])*
1724  *   where bound is integer, decimal or keywords 'min' or 'max.
1725  * RFC 7950 9.2.4:
1726  *  A range consists of an explicit value, or a lower-inclusive bound,
1727  *  two consecutive dots "..", and an upper-inclusive bound.  Multiple
1728  *  values or ranges can be given, separated by "|".  If multiple values
1729  *  or ranges are given, they all MUST be disjoint and MUST be in
1730  *  ascending order
1731  */
1732 static int
ys_populate_range(clicon_handle h,yang_stmt * ys)1733 ys_populate_range(clicon_handle h,
1734 		  yang_stmt    *ys)
1735 {
1736     int             retval = -1;
1737     yang_stmt      *yparent;         /* type */
1738     char           *origtype = NULL; /* orig type */
1739     yang_stmt      *yrestype;        /* resolved type */
1740     char           *restype;         /* resolved type */
1741     int             options = 0x0;
1742     uint8_t         fraction_digits;
1743     enum cv_type    cvtype = CGV_ERR;
1744 
1745     yparent = ys->ys_parent;     /* Find parent: type */
1746     if (yparent->ys_keyword != Y_TYPE){
1747 	clicon_err(OE_YANG, 0, "parent should be type");
1748 	goto done;
1749     }
1750     if (yang_type_resolve(ys, ys, (yang_stmt*)yparent, &yrestype,
1751 			  &options, NULL, NULL, NULL, &fraction_digits) < 0)
1752 	goto done;
1753     restype = yrestype?yrestype->ys_argument:NULL;
1754     if (nodeid_split(yang_argument_get(yparent), NULL, &origtype) < 0)
1755 	 goto done;
1756     /* This handles non-resolved also */
1757     if (clicon_type2cv(origtype, restype, ys, &cvtype) < 0)
1758 	goto done;
1759     if (!cv_isint(cvtype) && cvtype != CGV_DEC64){
1760 	clicon_err(OE_YANG, 0, "The range substatement only applies to int types, not to type: %s", origtype);
1761 	goto done;
1762     }
1763     if (range_parse(ys, cvtype, fraction_digits) < 0)
1764 	goto done;
1765     retval = 0;
1766   done:
1767     if (origtype)
1768 	free(origtype);
1769     return retval;
1770 }
1771 
1772 /*! Populate integer built-in length statement
1773  *
1774  * Create cvec variables "range_min" and "range_max". Assume parent is type.
1775  * @param[in] h    Clicon handle
1776  * @param[in] ys   The yang statement (length) to populate.
1777  *
1778  * Actually: len[..len] (| len[..len])*
1779  *   len is unsigned integer or keywords 'min' or 'max'
1780  *
1781  * From RFC 7950 Sec 9.4.4:
1782  *  A length range consists of an explicit value, or a lower bound, two
1783  *  consecutive dots "..", and an upper bound.  Multiple values or ranges
1784  *  can be given, separated by "|".  Length-restricting values MUST NOT
1785  *  be negative.  If multiple values or ranges are given, they all MUST
1786  *  be disjoint and MUST be in ascending order.
1787  */
1788 static int
ys_populate_length(clicon_handle h,yang_stmt * ys)1789 ys_populate_length(clicon_handle h,
1790 		   yang_stmt    *ys)
1791 {
1792     int             retval = -1;
1793     yang_stmt      *yparent;        /* type */
1794     enum cv_type    cvtype = CGV_ERR;
1795 
1796     yparent = ys->ys_parent;     /* Find parent: type */
1797     if (yparent->ys_keyword != Y_TYPE){
1798 	clicon_err(OE_YANG, 0, "parent should be type");
1799 	goto done;
1800     }
1801     cvtype = CGV_UINT64;
1802     if (range_parse(ys, cvtype, 0) < 0)
1803 	goto done;
1804     retval = 0;
1805   done:
1806     return retval;
1807 }
1808 
1809 /*! Sanity check yang type statement
1810  * XXX: Replace with generic parent/child type-check
1811  * @param[in] h    Clicon handle
1812  * @param[in] ys   The yang statement (type) to populate.
1813  */
1814 static int
ys_populate_type(clicon_handle h,yang_stmt * ys)1815 ys_populate_type(clicon_handle h,
1816 		 yang_stmt    *ys)
1817 
1818 {
1819     int             retval = -1;
1820     yang_stmt      *ybase;
1821 
1822     if (strcmp(ys->ys_argument, "decimal64") == 0){
1823 	if (yang_find(ys, Y_FRACTION_DIGITS, NULL) == NULL){
1824 	    clicon_err(OE_YANG, 0, "decimal64 type requires fraction-digits sub-statement");
1825 	    goto done;
1826 	}
1827     }
1828     else
1829     if (strcmp(ys->ys_argument, "identityref") == 0){
1830 	if ((ybase = yang_find(ys, Y_BASE, NULL)) == NULL){
1831 	    clicon_err(OE_YANG, 0, "identityref type requires base sub-statement");
1832 	    goto done;
1833 	}
1834 	if ((yang_find_identity(ys, ybase->ys_argument)) == NULL){
1835 	    clicon_err(OE_YANG, 0, "Identity %s not found (base type of %s)",
1836 		       ybase->ys_argument, ys->ys_argument);
1837 	    goto done;
1838 	}
1839     }
1840     retval = 0;
1841   done:
1842     return retval;
1843 }
1844 
1845 /*! Sanity check yang identity statement recursively and create derived id list
1846  *
1847  * Find base identities if any and add this identity to derived identity list.
1848  * Do this recursively
1849  * The derived identity list is a list of <module>:<id> pairs. Prefixes cannot
1850  * be used since they are local in scope.
1851  * @param[in] h     Clicon handle
1852  * @param[in] ys    The yang identity to populate.
1853  * @param[in] idref If set contains the derived identifier(NULL on top call)
1854  * @see validate_identityref  which in runtime validates actual values
1855  */
1856 static int
ys_populate_identity(clicon_handle h,yang_stmt * ys,char * idref)1857 ys_populate_identity(clicon_handle h,
1858 		     yang_stmt    *ys,
1859 		     char         *idref)
1860 {
1861     int             retval = -1;
1862     yang_stmt      *yc = NULL;
1863     yang_stmt      *ybaseid;
1864     cg_var         *cv;
1865     char           *baseid;
1866     char           *prefix = NULL;
1867     char           *id = NULL;
1868     cbuf           *cb = NULL;
1869     yang_stmt      *ymod;
1870     cvec           *idrefvec; /* Derived identityref list: (module:id)**/
1871 
1872     /* Top-call (no recursion) create idref
1873      * The idref is (here) in "canonical form": <module>:<id>
1874      */
1875     if (idref == NULL){
1876 	/* Create derived identity through prefix:id if not recursively called*/
1877 	if ((cb = cbuf_new()) == NULL){
1878 	    clicon_err(OE_UNIX, errno, "cbuf_new");
1879 	    goto done;
1880 	}
1881 	if (nodeid_split(yang_argument_get(ys), &prefix, &id) < 0)
1882 	    goto done;
1883 	if ((ymod = ys_module(ys)) == NULL){
1884 	    clicon_err(OE_YANG, ENOENT, "No module found");
1885 	    goto done;
1886 	}
1887 	cprintf(cb, "%s:%s", yang_argument_get(ymod), id);
1888 	idref = cbuf_get(cb);
1889     }
1890     /* Iterate through all base statements and check the base identity exists
1891      * AND populate the base identity recursively
1892      */
1893     yc = NULL;
1894     while ((yc = yn_each(ys, yc)) != NULL) {
1895 	if (yc->ys_keyword != Y_BASE)
1896 	    continue;
1897 	baseid = yang_argument_get(yc); /* on the form: prefix:id */
1898 	if (((ybaseid = yang_find_identity(ys, baseid))) == NULL){
1899 	    clicon_err(OE_YANG, ENOENT, "No such identity: %s", baseid);
1900 	    goto done;
1901 	}
1902 	//	    continue; /* root identity */
1903 	/* Check if derived id is already in base identifier
1904 	 * note that cvec is always created in ys_new()
1905 	 */
1906 	idrefvec = yang_cvec_get(ybaseid);
1907 	if (cvec_find(idrefvec, idref) != NULL)
1908 	    continue;
1909 	/* Add derived id to ybaseid */
1910 	if ((cv = cv_new(CGV_STRING)) == NULL){
1911 	    clicon_err(OE_UNIX, errno, "cv_new");
1912 	    goto done;
1913 	}
1914 	/* add prefix */
1915 	cv_name_set(cv, idref);
1916 	cvec_append_var(idrefvec, cv); /* cv copied */
1917 	if (cv){
1918 	    cv_free(cv);
1919 	    cv = NULL;
1920 	}
1921 	/* Transitive to the root */
1922 	if (ys_populate_identity(h, ybaseid, idref) < 0)
1923 	    goto done;
1924     }
1925     retval = 0;
1926   done:
1927     if (prefix)
1928 	free(prefix);
1929     if (id)
1930 	free(id);
1931     if (cb)
1932 	cbuf_free(cb);
1933     return retval;
1934 }
1935 
1936 /*! Return 1 if feature is enabled, 0 if not using the populated yang tree
1937  *
1938  * @param[in] yspec   yang specification
1939  * @param[in] module  Name of module
1940  * @param[in] feature Name of feature
1941  * @retval    0       Not found or not set
1942  * @retval    1       Found and set
1943  * XXX: should the in-param be h, ymod, or yspec?
1944  */
1945 int
if_feature(yang_stmt * yspec,char * module,char * feature)1946 if_feature(yang_stmt    *yspec,
1947 	   char         *module,
1948 	   char         *feature)
1949 {
1950     yang_stmt *ym; /* module */
1951     yang_stmt *yf; /* feature */
1952     cg_var    *cv;
1953 
1954     if ((ym = yang_find_module_by_name(yspec, module)) == NULL)
1955 	return 0;
1956     if ((yf = yang_find(ym, Y_FEATURE, feature)) == NULL)
1957 	return 0;
1958     if ((cv = yang_cv_get(yf)) == NULL)
1959 	return 0;
1960     return cv_bool_get(cv);
1961 }
1962 
1963 /*! Populate yang feature statement - set cv to 1 if enabled
1964  *
1965  * @param[in] h    Clicon handle
1966  * @param[in] ys   Feature yang statement to populate.
1967  */
1968 static int
ys_populate_feature(clicon_handle h,yang_stmt * ys)1969 ys_populate_feature(clicon_handle h,
1970 		    yang_stmt    *ys)
1971 {
1972     int        retval = -1;
1973     cxobj     *x;
1974     yang_stmt *ymod;
1975     int        found = 0;
1976     cg_var    *cv;
1977     char      *module;
1978     char      *feature;
1979     cxobj     *xc;
1980     char      *m;
1981     char      *f;
1982 
1983     /* get clicon config file in xml form */
1984     if ((x = clicon_conf_xml(h)) == NULL)
1985 	goto ok;
1986     if ((ymod = ys_module(ys)) == NULL){
1987 	clicon_err(OE_YANG, 0, "module not found");
1988 	goto done;
1989     }
1990     module = ymod->ys_argument;
1991     feature = ys->ys_argument;
1992     xc = NULL;
1993     while ((xc = xml_child_each(x, xc, CX_ELMNT)) != NULL && found == 0) {
1994 	m = NULL;
1995 	f = NULL;
1996 	if (strcmp(xml_name(xc), "CLICON_FEATURE") != 0)
1997 	    continue;
1998 	/* CLICON_FEATURE is on the form <module>:<feature>.
1999 	 * Split on colon to get module(m) and feature(f) respectively */
2000 	if (nodeid_split(xml_body(xc), &m, &f) < 0)
2001 	    goto done;
2002 	if (m && f &&
2003 	    (strcmp(m,"*")==0 ||
2004 	     strcmp(m, module)==0) &&
2005 	    (strcmp(f,"*")==0 ||
2006 	     strcmp(f, feature)==0))
2007 	    found = 1;
2008 	if (m) free(m);
2009 	if (f) free(f);
2010     }
2011     if ((cv = cv_new(CGV_BOOL)) == NULL){
2012 	clicon_err(OE_YANG, errno, "cv_new");
2013 	goto done;
2014     }
2015     cv_name_set(cv, feature);
2016     cv_bool_set(cv, found);
2017     if (found)
2018 	clicon_debug(2, "%s %s:%s", __FUNCTION__, module, feature);
2019     ys->ys_cv = cv;
2020  ok:
2021     retval = 0;
2022  done:
2023     return retval;
2024 }
2025 
2026 /*! Populate the unique statement with a cvec
2027  * @param[in] h    Clicon handle
2028  * @param[in] ys   The yang statement (unique) to populate.
2029  */
2030 static int
ys_populate_unique(clicon_handle h,yang_stmt * ys)2031 ys_populate_unique(clicon_handle h,
2032 		   yang_stmt    *ys)
2033 {
2034     if (ys->ys_cvec)
2035 	cvec_free(ys->ys_cvec);
2036     if ((ys->ys_cvec = yang_arg2cvec(ys, " ")) == NULL)
2037 	return -1;
2038     return 0;
2039 }
2040 
2041 /*! Populate unknown node with extension
2042  * @param[in] h    Clicon handle
2043  * @param[in] ys   The yang statement (unknown) to populate.
2044  * RFC 7950 Sec 7.19:
2045  * If no "argument" statement is present, the keyword expects no argument when
2046  * it is used.
2047  */
2048 static int
ys_populate_unknown(clicon_handle h,yang_stmt * ys)2049 ys_populate_unknown(clicon_handle h,
2050 		    yang_stmt    *ys)
2051 {
2052     int        retval = -1;
2053     yang_stmt *ymod;
2054     yang_stmt *yext;  /* extension */
2055     char      *prefix = NULL;
2056     char      *id = NULL;
2057     char      *argument; /* This is the unknown optional argument */
2058     cg_var    *cv;
2059 
2060     /* Find extension, if found, store it as unknown, if not,
2061        break for error */
2062     if (nodeid_split(yang_argument_get(ys), &prefix, &id) < 0)
2063 	goto done;
2064     if ((ymod = yang_find_module_by_prefix(ys, prefix)) == NULL){
2065 	clicon_err(OE_YANG, ENOENT, "Extension %s:%s, module not found", prefix, id);
2066 	goto done;
2067     }
2068     if ((yext = yang_find(ymod, Y_EXTENSION, id)) == NULL){
2069 	clicon_err(OE_YANG, ENOENT, "Extension %s:%s not found", prefix, id);
2070 	goto done;
2071     }
2072     /* Optional argument (only if "argument") - save it in ys_cv */
2073     if ((cv = yang_cv_get(ys)) != NULL &&
2074 	(argument = cv_string_get(cv)) != NULL){
2075 	if (yang_find(yext, Y_ARGUMENT, NULL) == NULL &&
2076 	    argument != NULL){
2077 	    clicon_err(OE_YANG, 0, "No argument specified in extension %s, but argument %s present when used", yang_argument_get(ys), argument);
2078 	    goto done;
2079 	}
2080     }
2081 #ifdef XML_EXPLICIT_INDEX
2082     /* Add explicit index extension */
2083     if ((retval = yang_search_index_extension(h, yext, ys)) < 0) {
2084 	clicon_debug(1, "plugin_extension() failed");
2085 	return -1;
2086     }
2087 #endif
2088     /* Make extension callbacks that may alter yang structure */
2089     if (clixon_plugin_extension_all(h, yext, ys) < 0)
2090 	goto done;
2091 
2092     retval = 0;
2093  done:
2094     if (prefix)
2095 	free(prefix);
2096     if (id)
2097 	free(id);
2098     return retval;
2099 }
2100 
2101 /*! Populate modules / submodules
2102  * @param[in] h    Clicon handle
2103  * @param[in] ys   The yang statement (module/submodule) to populate.
2104  *
2105  * Check RFC 7950: 7.1.4: All prefixes, including the prefix for the module itself,
2106  * MUST be unique within the module or submodule.
2107  */
2108 static int
ys_populate_module_submodule(clicon_handle h,yang_stmt * ym)2109 ys_populate_module_submodule(clicon_handle h,
2110 			     yang_stmt    *ym)
2111 {
2112     int        retval = -1;
2113     yang_stmt *yp;
2114     yang_stmt *yi;
2115     yang_stmt *yi2; /* remaining */
2116     char      *p0 = NULL;
2117     char      *pi;
2118     char      *pi2; /* remaining */
2119 
2120     /* Modules but not submodules have prefixes */
2121     if ((yp = yang_find(ym, Y_PREFIX, NULL)) != NULL)
2122 	p0 = yang_argument_get(yp);
2123     yi = NULL;
2124     while ((yi = yn_each(ym, yi)) != NULL) {
2125 	if (yang_keyword_get(yi) != Y_IMPORT)
2126 	    continue;
2127 	yp = yang_find(yi, Y_PREFIX, NULL);
2128 	pi = yang_argument_get(yp);
2129 	if (p0 && strcmp(p0, pi) == 0){ 	/* Check top-level */
2130 	    clicon_err(OE_YANG, EFAULT, "Prefix %s in module %s is not unique but should be (see RFC 7950 7.1.4)",
2131 		       pi, yang_argument_get(ym));
2132 	    goto done;
2133 	}
2134 	/* Check rest of imports */
2135 	yi2 = yi;
2136 	while ((yi2 = yn_each(ym, yi2)) != NULL) {
2137 	    if (yang_keyword_get(yi2) != Y_IMPORT)
2138 		continue;
2139 	    yp = yang_find(yi2, Y_PREFIX, NULL);
2140 	    pi2 = yang_argument_get(yp);
2141 	    if (strcmp(pi2, pi) == 0){
2142 		clicon_err(OE_YANG, EFAULT, "Prefix %s in module %s is not unique but should be (see RFC 7950 7.1.4)",
2143 			   pi, yang_argument_get(ym));
2144 		goto done;
2145 	    }
2146 	}
2147     }
2148     retval = 0;
2149  done:
2150     return retval;
2151 }
2152 
2153 /*! Populate with cligen-variables, default values, etc. Sanity checks on complete tree.
2154  *
2155  * @param[in]  ys  Yang statement
2156  * @param[in]  arg Argument - in effect Clicon handle
2157  * Preferably run this command using yang_apply
2158  * Done in 2nd pass after complete parsing to be sure to have a complete
2159  * parse-tree
2160 
2161  * After this pass, cv:s are set for LEAFs and LEAF-LISTs
2162  * @see ys_parse_sub   for first pass and what can be assumed
2163  * @see ys_populate2   for after grouping expand and augment
2164  * (there may be more functions (all?) that may be moved to ys_populate2)
2165  */
2166 int
ys_populate(yang_stmt * ys,void * arg)2167 ys_populate(yang_stmt    *ys,
2168 	    void         *arg)
2169 {
2170     int           retval = -1;
2171     clicon_handle h = (clicon_handle)arg;
2172 
2173     switch(ys->ys_keyword){
2174     case Y_IDENTITY:
2175 	if (ys_populate_identity(h, ys, NULL) < 0)
2176 	    goto done;
2177 	break;
2178     case Y_LENGTH:
2179 	if (ys_populate_length(h, ys) < 0)
2180 	    goto done;
2181 	break;
2182     case Y_LIST:
2183 	if (ys_populate_list(h, ys) < 0)
2184 	    goto done;
2185 	break;
2186     case Y_MODULE:
2187     case Y_SUBMODULE:
2188 	if (ys_populate_module_submodule(h, ys) < 0)
2189 	    goto done;
2190 	break;
2191     case Y_RANGE:
2192 	if (ys_populate_range(h, ys) < 0)
2193 	    goto done;
2194 	break;
2195     case Y_TYPE:
2196 	if (ys_populate_type(h, ys) < 0)
2197 	    goto done;
2198 	break;
2199     case Y_UNIQUE:
2200 	if (ys_populate_unique(h, ys) < 0)
2201 	    goto done;
2202 	break;
2203     case Y_UNKNOWN:
2204 	if (ys_populate_unknown(h, ys) < 0)
2205 	    goto done;
2206 	break;
2207     default:
2208 	break;
2209     }
2210     retval = 0;
2211   done:
2212     return retval;
2213 }
2214 
2215 /*! Run after grouping expand and augment
2216  * @see ys_populate   run before grouping expand and augment
2217  */
2218 int
ys_populate2(yang_stmt * ys,void * arg)2219 ys_populate2(yang_stmt    *ys,
2220 	     void         *arg)
2221 {
2222     int           retval = -1;
2223     clicon_handle h = (clicon_handle)arg;
2224 
2225     switch(ys->ys_keyword){
2226     case Y_LEAF:
2227     case Y_LEAF_LIST:
2228 	if (ys_populate_leaf(h, ys) < 0)
2229 	    goto done;
2230 	break;
2231     case Y_MANDATORY: /* call yang_mandatory() to check if set */
2232     case Y_CONFIG:
2233 	if (ys_parse(ys, CGV_BOOL) == NULL)
2234 	    goto done;
2235 	break;
2236     default:
2237 	break;
2238     }
2239     retval = 0;
2240   done:
2241     return retval;
2242 }
2243 
2244 /*! Handle complexity of if-feature node
2245  * @param[in] h   Clixon handle
2246  * @param[in] ys  Yang if-feature statement
2247  * @retval   -1   Error
2248  * @retval    0   Feature not enabled: remove yt
2249  * @retval    1   OK
2250  * @note if-feature syntax is restricted to single, and, or, syntax, such as "a or b"
2251  * but RFC7950 allows for nested expr/term/factor syntax.
2252  * XXX This should really be parsed in yang/lex.
2253  */
2254 static int
yang_if_feature(clicon_handle h,yang_stmt * ys)2255 yang_if_feature(clicon_handle h,
2256 		yang_stmt    *ys)
2257 {
2258     int         retval = -1;
2259     char      **vec = NULL;
2260     int         nvec;
2261     char       *f;
2262     int         i;
2263     int         j;
2264     char       *prefix = NULL;
2265     char       *feature = NULL;
2266     yang_stmt  *ymod;  /* module yang node */
2267     yang_stmt  *yfeat; /* feature yang node */
2268     int         opand = -1; /* -1:not set, 0:or, 1:and */
2269     int         enabled = 0;
2270 
2271     if ((vec = clicon_strsep(ys->ys_argument, " \t\r\n", &nvec)) == NULL)
2272 	goto done;
2273     /* Two steps: first detect operators
2274      * Step 1: support "a" or "a or b or c" or "a and b and c "
2275      */
2276     j = 0;
2277     for (i=0; i<nvec; i++){
2278 	f = vec[i];
2279 	if (strcmp(f, "") == 0) /* skip empty */
2280 	    continue;
2281 	if ((j++)%2==0) /* only keep odd i:s 1,3,... */
2282 	    continue;
2283 	/* odd i: operator "and" or "or" */
2284 	if (strcmp(f, "or") == 0){
2285 	    switch (opand){
2286 	    case -1:
2287 		if (i != 1){
2288 		    clicon_err(OE_YANG, EINVAL, "Syntax error IF_FEATURE \"%s\" (only single if-feature-expr and/or lists allowed)", ys->ys_argument);
2289 		    goto done;
2290 		}
2291 		opand = 0;
2292 		break;
2293 	    case 0:
2294 		break;
2295 	    case 1:
2296 		clicon_err(OE_YANG, EINVAL, "Syntax error IF_FEATURE \"%s\" (only single if-feature-expr and/or lists allowed)", ys->ys_argument);
2297 		goto done;
2298 		break;
2299 	    }
2300 	}
2301 	else if (strcmp(f, "and") == 0){
2302 	    switch (opand){
2303 	    case -1:
2304 		if (i != 1){
2305 		    clicon_err(OE_YANG, EINVAL, "Syntax error IF_FEATURE \"%s\" (only single if-feature-expr and/or lists allowed)", ys->ys_argument);
2306 		    goto done;
2307 		}
2308 		opand = 1;
2309 		break;
2310 	    case 0:
2311 		clicon_err(OE_YANG, EINVAL, "Syntax error IF_FEATURE \"%s\" (only single if-feature-expr and/or lists allowed)", ys->ys_argument);
2312 		goto done;
2313 		break;
2314 	    case 1:
2315 		break;
2316 	    }
2317 	}
2318 	else{
2319 	    clicon_err(OE_YANG, EINVAL, "Syntax error IF_FEATURE \"%s\" (only single if-feature-expr and/or lists allowed)", ys->ys_argument);
2320 	    goto done;
2321 	}
2322     } /* for step 1 */
2323     if (j%2 == 0){ /* Must be odd: eg a / "a or b" etc */
2324 	clicon_err(OE_YANG, EINVAL, "Syntax error IF_FEATURE \"%s\" (only single if-feature-expr and/or lists allowed)", ys->ys_argument);
2325 	goto done;
2326     }
2327 
2328     if (opand == -1) /* Uninitialized means single operand */
2329 	opand = 1;
2330     if (opand) /* if AND,  start as enabled, if OR start as disabled */
2331 	enabled = 1;
2332     else
2333 	enabled = 0;
2334     /* Step 2: Boolean operations on operands */
2335     j = 0;
2336     for (i=0; i<nvec; i++){
2337 	f = vec[i];
2338 	if (strcmp(f, "") == 0) /* skip empty */
2339 	    continue;
2340 	if ((j++)%2==1) /* only keep even i:s 0,2,... */
2341 	    continue;
2342 	if (nodeid_split(f, &prefix, &feature) < 0)
2343 	    goto done;
2344 	/* Specifically need to handle? strcmp(prefix, myprefix)) */
2345 	if (prefix == NULL)
2346 	    ymod = ys_module(ys);
2347 	else
2348 	    ymod = yang_find_module_by_prefix(ys, prefix);
2349 	/* Check if feature exists, and is set, otherwise remove */
2350 	if ((yfeat = yang_find(ymod, Y_FEATURE, feature)) == NULL){
2351 	    clicon_err(OE_YANG, EINVAL, "Yang module %s has IF_FEATURE %s, but no such FEATURE statement exists",
2352 		       ymod?yang_argument_get(ymod):"none",
2353 		       feature);
2354 	    goto done;
2355 	}
2356 	/* Check if this feature is enabled or not
2357 	 * Continue loop to catch unbound features and make verdict at end
2358 	 */
2359 	if (yfeat->ys_cv == NULL || !cv_bool_get(yfeat->ys_cv)){    /* disabled */
2360 	    /* if AND then this is permanently disabled */
2361 	    if (opand && enabled)
2362 		enabled = 0;
2363 	}
2364 	else{                                                       /* enabled */
2365 	    /* if OR then this is permanently enabled */
2366 	    if (!opand && !enabled)
2367 		enabled = 1;
2368 	}
2369 	if (prefix){
2370 	    free(prefix);
2371 	    prefix = NULL;
2372 	}
2373 	if (feature){
2374 	    free(feature);
2375 	    feature = NULL;
2376 	}
2377     }
2378     if (!enabled)
2379 	goto disabled;
2380     retval = 1;
2381  done:
2382     if (vec)
2383 	free(vec);
2384     if (prefix)
2385 	free(prefix);
2386     if (feature)
2387 	free(feature);
2388     return retval;
2389  disabled:
2390     retval = 0;  /* feature not enabled */
2391     goto done;
2392 }
2393 
2394 /*! Find feature and if-feature nodes, check features and remove disabled nodes
2395  * @param[in] h   Clixon handle
2396  * @param[in] yt  Yang statement
2397  * @retval   -1   Error
2398  * @retval    0   Feature not enabled: remove yt
2399  * @retval    1   OK
2400  * @note On return 1 the over-lying function need to remove yt from its parent
2401  * @note cannot use yang_apply here since child-list is modified (destructive)
2402  * @note if-feature syntax is restricted to single, and, or, syntax, such as "a or b"
2403  */
2404 int
yang_features(clicon_handle h,yang_stmt * yt)2405 yang_features(clicon_handle h,
2406 	      yang_stmt    *yt)
2407 {
2408     int        retval = -1;
2409     int        i;
2410     int        j;
2411     yang_stmt *ys = NULL;
2412     int        ret;
2413 
2414     i = 0;
2415     while (i<yt->ys_len){ /* Note, children may be removed */
2416 	ys = yt->ys_stmt[i];
2417 	if (ys->ys_keyword == Y_IF_FEATURE){
2418 	    if ((ret = yang_if_feature(h, ys)) < 0)
2419 		goto done;
2420 	    if (ret == 0)
2421 		goto disabled;
2422 	}
2423 	else
2424 	    if (ys->ys_keyword == Y_FEATURE){
2425 		if (ys_populate_feature(h, ys) < 0)
2426 		    goto done;
2427 	    } else switch (yang_features(h, ys)){
2428 	    case -1: /* error */
2429 		goto done;
2430 		break;
2431 	    case 0: /* disabled: remove ys */
2432 		for (j=i+1; j<yt->ys_len; j++)
2433 		    yt->ys_stmt[j-1] = yt->ys_stmt[j];
2434 		yt->ys_len--;
2435 		yt->ys_stmt[yt->ys_len] = NULL;
2436 		ys_free(ys);
2437 		continue; /* Don't increment i */
2438 		break;
2439 	    default: /* ok */
2440 		break;
2441 	    }
2442 	i++;
2443     }
2444     retval = 1;
2445  done:
2446     return retval;
2447  disabled:
2448     retval = 0;  /* feature not enabled */
2449     goto done;
2450 }
2451 
2452 /*! Apply a function call recursively on all yang-stmt s recursively
2453  *
2454  * Recursively traverse all yang-nodes in a parse-tree and apply fn(arg) for
2455  * each object found. The function is called with the yang-stmt and an
2456  * argument as args.
2457  * The tree is traversed depth-first, which at least guarantees that a parent is
2458  * traversed before a child.
2459  * @param[in]  yn   yang node
2460  * @param[in]  key  yang keyword to use as filer or -1 for all
2461  * @param[in]  fn   Callback
2462  * @param[in]  arg  Argument
2463  * @retval    -1    Error, aborted at first error encounter
2464  * @retval     0    OK, all nodes traversed
2465  * @retval     n    OK, aborted at first encounter of first match
2466  * @code
2467  * int ys_fn(yang_stmt *ys, void *arg)
2468  * {
2469  *   return 0;
2470  * }
2471  * yang_apply(ys, Y_TYPE, ys_fn, NULL);
2472  * @endcode
2473  * @note do not delete or move around any children during this function
2474  */
2475 int
yang_apply(yang_stmt * yn,enum rfc_6020 keyword,yang_applyfn_t fn,void * arg)2476 yang_apply(yang_stmt     *yn,
2477 	   enum rfc_6020  keyword,
2478 	   yang_applyfn_t fn,
2479 	   void          *arg)
2480 {
2481     int        retval = -1;
2482     yang_stmt *ys = NULL;
2483     int        i;
2484     int        ret;
2485 
2486     for (i=0; i<yn->ys_len; i++){
2487 	ys = yn->ys_stmt[i];
2488 	if ((int)keyword == -1 || keyword == ys->ys_keyword){
2489 	    if ((ret = fn(ys, arg)) < 0)
2490 		goto done;
2491 	    if (ret > 0){
2492 		retval = ret;
2493 		goto done;
2494 	    }
2495 	}
2496 	if ((ret = yang_apply(ys, keyword, fn, arg)) < 0)
2497 	    goto done;
2498 	if (ret > 0){
2499 	    retval = ret;
2500 	    goto done;
2501 	}
2502     }
2503     retval = 0;
2504   done:
2505     return retval;
2506 }
2507 
2508 /*! Check if a node is a yang "data node"
2509  * @param[in]  ys  Yang statement node
2510  * @retval     0   Yang node is NOT a data node
2511  * @retval   !=0   Yang node IS a data noed
2512  * @see RFC7950 Sec 3:
2513  *   o  data node: A node in the schema tree that can be instantiated in a
2514  *      data tree.  One of container, leaf, leaf-list, list, anydata, and
2515  *      anyxml.
2516  */
2517 int
yang_datanode(yang_stmt * ys)2518 yang_datanode(yang_stmt *ys)
2519 {
2520     enum rfc_6020 keyw;
2521 
2522     keyw = yang_keyword_get(ys);
2523     return (keyw == Y_CONTAINER ||
2524 	    keyw == Y_LEAF ||
2525 	    keyw == Y_LIST ||
2526 	    keyw == Y_LEAF_LIST ||
2527 	    keyw == Y_ANYXML ||
2528 	    keyw == Y_ANYDATA);
2529 }
2530 
2531 /*! All the work for schema_nodeid functions both absolute and descendant
2532  *
2533  * @param[in]  yn    Yang node. For absolute schemanodeids this should be a module, otherwise any yang
2534  * @param[in]  cvv   Schema-node path encoded as a name/value pair list.
2535  * @param[in]  nsc   Namespace context from yang for the prefixes (names) of cvv
2536  * @param[out] yres  Result yang statement node, or NULL if not found
2537  * @retval    -1     Error, with clicon_err called
2538  * @retval     0     OK
2539  *   A schema node identifier consists of a path of identifiers, separated by slashes ("/").
2540  *   References to identifiers defined in external modules MUST be
2541  *   qualified with appropriate prefixes, and references to identifiers
2542  *   defined in the current module and its submodules MAY use a prefix.
2543  * prefixes are implemented by cvv names, and id:s by cvv strings.
2544  * A namespace context of the original module is nsc as prefix context.
2545  *
2546  * @see RFC7950 Sec 6.5
2547  */
2548 static int
schema_nodeid_iterate(yang_stmt * yn,cvec * nodeid_cvv,cvec * nsc,yang_stmt ** yres)2549 schema_nodeid_iterate(yang_stmt    *yn,
2550 		      cvec         *nodeid_cvv,
2551 		      cvec         *nsc,
2552 		      yang_stmt   **yres)
2553 {
2554     int              retval = -1;
2555     yang_stmt       *ymod;
2556     char            *prefix; /* node-identifier     = [prefix ":"] identifier */
2557     char            *id;
2558     yang_stmt       *ys;
2559     yang_stmt       *ym2;
2560     yang_stmt       *yp;
2561     cg_var          *cv;
2562     char            *ns;
2563     yang_stmt       *yspec;
2564 
2565     yspec = ys_spec(yn);
2566     yp = yn;
2567     /* Iterate over node identifiers /prefix:id/... */
2568     cv = NULL;
2569     while ((cv = cvec_each(nodeid_cvv, cv)) != NULL){
2570 	prefix = cv_name_get(cv);
2571 	id = cv_string_get(cv);
2572 	/* Top level is repeated from abs case, but here this is done to match with
2573 	 * matching module below
2574 	 * Get namespace */
2575 	if ((ns = xml_nsctx_get(nsc, prefix)) == NULL){
2576 	    clicon_err(OE_YANG, EFAULT, "No namespace for prefix: %s in schema node identifier in module %s",
2577 		       prefix,
2578 		       yang_argument_get(ys_module(yn)));
2579 	    goto done;
2580 	}
2581 	/* Get yang module */
2582 	if ((ymod = yang_find_module_by_namespace(yspec, ns)) == NULL){
2583 	    clicon_err(OE_YANG, EFAULT, "No module for namespace: %s", ns);
2584 	    goto done;
2585 	}
2586        /* Iterate over children of current node to get a match
2587 	* XXX namespace?????
2588 	*/
2589 	ys = NULL;
2590 	while ((ys = yn_each(yp, ys)) != NULL) {
2591 	    if (!yang_schemanode(ys))
2592 		continue;
2593 
2594 	    /* some keys dont have arguments, match on key */
2595 	    if (ys->ys_keyword == Y_INPUT || ys->ys_keyword == Y_OUTPUT){
2596 		if (strcmp(id, yang_key2str(ys->ys_keyword)) == 0){
2597 		    break;
2598 		}
2599 	    }
2600 	    else {
2601 		if (ys->ys_argument && strcmp(id, ys->ys_argument) == 0){
2602 		    /* Also check for right prefix/module */
2603 		    ym2 = ys->ys_mymodule?ys->ys_mymodule:ys_module(ys);
2604 		    if (ym2 == ymod)
2605 			break;
2606 		}
2607 	    }
2608 	} /* while ys */
2609 	if (ys == NULL){
2610 	    clicon_debug(1, "%s: %s not found", __FUNCTION__, id);
2611 	    goto ok;
2612 	}
2613 	yp = ys;
2614     } /* while cv */
2615     assert(yp && yang_schemanode((yang_stmt*)yp));
2616     *yres = (yang_stmt*)yp;
2617  ok:
2618     retval = 0;
2619  done:
2620     return retval;
2621 }
2622 
2623 /*! Given an absolute schema-nodeid (eg /a/b/c) find matching yang spec
2624  * @param[in]  yspec         Yang specification.
2625  * @param[in]  yn            Original yang stmt (where call is made) if any
2626  * @param[in]  schema_nodeid Absolute schema-node-id, ie /a/b
2627  * @param[in]  keyword       A schemode of this type, or -1 if any
2628  * @param[out] yres          Result yang statement node, or NULL if not found
2629  * @retval    -1             Error, with clicon_err called
2630  * @retval     0             OK , with result in yres
2631  * Assume schema nodeid:s have prefixes, (actually the first).
2632  * @see RFC7950 6.5
2633  * o  schema node: A node in the schema tree.  One of action, container,
2634  *    leaf, leaf-list, list, choice, case, rpc, input, output,
2635  *    notification, anydata, and anyxml.
2636  * Used in yang: deviation, top-level augment
2637  * @see yang_desc_schema_nodeid
2638  */
2639 int
yang_abs_schema_nodeid(yang_stmt * yn,char * schema_nodeid,yang_stmt ** yres)2640 yang_abs_schema_nodeid(yang_stmt    *yn,
2641 		       char         *schema_nodeid,
2642 		       yang_stmt   **yres)
2643 {
2644     int           retval = -1;
2645     cvec         *nodeid_cvv = NULL;
2646     cvec         *nsc = NULL;
2647     cg_var       *cv;
2648     char         *prefix;
2649     char         *ns;
2650     yang_stmt    *yspec;
2651     yang_stmt    *ymod;
2652     char         *str;
2653 
2654     *yres = NULL;
2655     yspec = ys_spec(yn);
2656     /* check absolute schema_nodeid */
2657     if (schema_nodeid[0] != '/'){
2658 	clicon_err(OE_YANG, EINVAL, "absolute schema nodeid should start with /");
2659 	goto done;
2660     }
2661     /* Split nodeid on the form /p0:i0/p1:i1 to a cvec with [name:p0 value:i0][...]
2662      */
2663     if (str2cvec(schema_nodeid, '/', ':', &nodeid_cvv) < 0)
2664 	goto done;
2665     if (cvec_len(nodeid_cvv) == 0)
2666 	goto ok;
2667     /* If p0 is NULL an entry will be: [i0] which needs to be transformed to [NULL:i0] */
2668     cv = NULL;
2669     while ((cv = cvec_each(nodeid_cvv, cv)) != NULL){
2670 	if ((str = cv_string_get(cv)) == NULL || !strlen(str)){
2671 	    if (cv_string_set(cv, cv_name_get(cv)) < 0){
2672 		clicon_err(OE_UNIX, errno, "cv_string_set");
2673 		goto done;
2674 	    }
2675 	    cv_name_set(cv, NULL);
2676 	}
2677     }
2678     /* Make a namespace context from yang for the prefixes (names) of nodeid_cvv */
2679     if (xml_nsctx_yang(yn, &nsc) < 0)
2680 	goto done;
2681     /* Since this is an _absolute_ schema nodeid start from top
2682      * Get namespace */
2683     cv = cvec_i(nodeid_cvv, 0);
2684     prefix = cv_name_get(cv);
2685     if ((ns = xml_nsctx_get(nsc, prefix)) == NULL){
2686 	clicon_err(OE_YANG, EFAULT, "No namespace for prefix: %s in schema node identifier: %s in module %s",
2687 		   prefix, schema_nodeid, yang_argument_get(ys_module(yn)));
2688 	goto done;
2689     }
2690     /* Get yang module */
2691     if ((ymod = yang_find_module_by_namespace(yspec, ns)) == NULL){
2692 	clicon_err(OE_YANG, EFAULT, "No module for namespace: %s in schema node identifier: %s",
2693 		   ns, schema_nodeid);
2694 	goto done;
2695     }
2696     /* Iterate through cvv to find schemanode using ymod as starting point (since it is absolute) */
2697     if (schema_nodeid_iterate(ymod, nodeid_cvv, nsc, yres) < 0)
2698 	goto done;
2699  ok:
2700     retval = 0;
2701  done:
2702     if (nodeid_cvv)
2703 	cvec_free(nodeid_cvv);
2704     if (nsc)
2705 	cvec_free(nsc);
2706     return retval;
2707 }
2708 
2709 /*! Given a descendant schema-nodeid (eg a/b/c) find matching yang spec
2710  * @param[in]  yn            Yang node
2711  * @param[in]  schema_nodeid Descendant schema-node-id, ie a/b
2712  * @param[in]  keyword       A schemode of this type, or -1 if any
2713  * @param[out] yres          First yang node matching schema nodeid
2714  * @retval     0             OK
2715  * @retval    -1             Error, with clicon_err called
2716  * Used in yang: unique, refine, uses augment
2717  * @see yang_abs_schema_nodeid
2718  */
2719 int
yang_desc_schema_nodeid(yang_stmt * yn,char * schema_nodeid,yang_stmt ** yres)2720 yang_desc_schema_nodeid(yang_stmt    *yn,
2721 			char         *schema_nodeid,
2722 			yang_stmt   **yres)
2723 {
2724     int           retval = -1;
2725     cvec         *nodeid_cvv = NULL;
2726     cg_var       *cv;
2727     char         *str;
2728     cvec         *nsc = NULL;
2729 
2730     if (schema_nodeid == NULL || strlen(schema_nodeid) == 0){
2731 	clicon_err(OE_YANG, EINVAL, "nodeid is empty");
2732 	goto done;
2733     }
2734     *yres = NULL;
2735     /* check absolute schema_nodeid */
2736     if (schema_nodeid[0] == '/'){
2737 	clicon_err(OE_YANG, EINVAL, "descendant schema nodeid should not start with /");
2738 	goto done;
2739     }
2740     /* Split nodeid on the form /p0:i0/p1:i1 to a cvec with [name:p0 value:i0][...]
2741      */
2742     if (str2cvec(schema_nodeid, '/', ':', &nodeid_cvv) < 0)
2743 	goto done;
2744     if (cvec_len(nodeid_cvv) == 0)
2745 	goto ok;
2746     /* If p0 is NULL an entry will be: [i0] which needs to be transformed to [NULL:i0] */
2747     cv = NULL;
2748     while ((cv = cvec_each(nodeid_cvv, cv)) != NULL){
2749 	if ((str = cv_string_get(cv)) == NULL || !strlen(str)){
2750 	    if (cv_string_set(cv, cv_name_get(cv)) < 0){
2751 		clicon_err(OE_UNIX, errno, "cv_string_set");
2752 		goto done;
2753 	    }
2754 	    cv_name_set(cv, NULL);
2755 	}
2756     }
2757     /* Make a namespace context from yang for the prefixes (names) of nodeid_cvv */
2758     if (xml_nsctx_yang(yn, &nsc) < 0)
2759 	goto done;
2760     /* Iterate through cvv to find schemanode using yn as relative starting point */
2761     if (schema_nodeid_iterate(yn, nodeid_cvv, nsc, yres) < 0)
2762 	goto done;
2763  ok:
2764     retval = 0;
2765  done:
2766     if (nsc)
2767 	cvec_free(nsc);
2768     if (nodeid_cvv)
2769 	cvec_free(nodeid_cvv);
2770     return retval;
2771 }
2772 
2773 /*! Check if this leaf is mandatory or not
2774  * Note: one can cache this value in ys_cvec instead of functionally evaluating it.
2775  * @retval 1 yang statement is leaf and it has a mandatory sub-stmt with value true
2776  * @retval 0 The negation of conditions for return value 1.
2777  * @see RFC7950 Sec 3:
2778  *   o  mandatory node: A mandatory node is one of:
2779  *      1)  A leaf, choice, anydata, or anyxml node with a "mandatory"
2780  *         statement with the value "true".
2781  *      2) # see below
2782  *      3)  A container node without a "presence" statement and that has at
2783  *         least one mandatory node as a child.
2784  *
2785  * @note There is also this statement
2786  *      2)  A list or leaf-list node with a "min-elements" statement with a
2787  *         value greater than zero.
2788  * which we ignore here since:
2789  *      (a) it does not consider the XML siblings and  therefore returns false positives
2790  *      (b) where the actual check is catched by check_list_unique_minmax()
2791  */
2792 int
yang_mandatory(yang_stmt * ys)2793 yang_mandatory(yang_stmt *ys)
2794 {
2795     yang_stmt *ym;
2796 
2797     /* 1) A leaf, choice, anydata, or anyxml node with a "mandatory"
2798      *    statement with the value "true". */
2799     if (ys->ys_keyword == Y_LEAF || ys->ys_keyword == Y_CHOICE ||
2800 	ys->ys_keyword == Y_ANYDATA || ys->ys_keyword == Y_ANYXML){
2801 	if ((ym = yang_find(ys, Y_MANDATORY, NULL)) != NULL){
2802 	    if (ym->ys_cv != NULL) /* shouldnt happen */
2803 		return cv_bool_get(ym->ys_cv);
2804 	}
2805     }
2806 #if 0 /* See note above */
2807     /* 2) A list or leaf-list node with a "min-elements" statement with a
2808      *    value greater than zero. */
2809     else if (ys->ys_keyword == Y_LIST || ys->ys_keyword == Y_LEAF_LIST){
2810 	if ((ym = yang_find(ys, Y_MIN_ELEMENTS, NULL)) != NULL){
2811 	    cv = yang_cv_get(ym);
2812 	    return cv_uint32_get(cv) > 0; /* Not true if XML considered */
2813 	}
2814     }
2815 #endif
2816     /* 3) A container node without a "presence" statement and that has at
2817      *    least one mandatory node as a child. */
2818     else if (ys->ys_keyword == Y_CONTAINER &&
2819 	     yang_find(ys, Y_PRESENCE, NULL) == NULL){
2820 	yang_stmt *yc;
2821 	int i;
2822 	for (i=0; i<ys->ys_len; i++){
2823 	    yc = ys->ys_stmt[i];
2824 	    if (yang_mandatory(yc))
2825 		return 1;
2826 	}
2827     }
2828     return 0;
2829 }
2830 
2831 /*! Return config state of this node
2832  * @param[in] ys  Yang statement
2833  * @retval    0   If node has a config sub-statement and it is false
2834  * @retval    1   If node has not config sub-statement or it is true
2835  * @see yang_config_ancestor  which also takes ancestors into account, which you should normally do.
2836  */
2837 int
yang_config(yang_stmt * ys)2838 yang_config(yang_stmt *ys)
2839 {
2840     yang_stmt *ym;
2841 
2842     if ((ym = yang_find(ys, Y_CONFIG, NULL)) != NULL){
2843 	if (ym->ys_cv == NULL) /* shouldnt happen */
2844 	    return 1;
2845 	return cv_bool_get(ym->ys_cv);
2846     }
2847     return 1;
2848 }
2849 
2850 /*! Return config state of this node taking parents/ancestors into account
2851  *
2852  * config statement is default true.
2853  * @param[in] ys  Yang statement
2854  * @retval    0   Node or one of its ancestor has config false
2855  * @retval    1   Neither node nor any of its ancestors has config false
2856  */
2857 int
yang_config_ancestor(yang_stmt * ys)2858 yang_config_ancestor(yang_stmt *ys)
2859 {
2860     yang_stmt *yp;
2861 
2862     yp = ys;
2863     do {
2864 	if (yang_config(yp) == 0)
2865 	    return 0;
2866     } while((yp = yang_parent_get(yp)) != NULL);
2867     return 1;
2868 }
2869 
2870 /*! Given a yang node, translate the argument string to a cv vector
2871  *
2872  * @param[in]  ys         Yang statement
2873  * @param[in]  delimiter  Delimiter character (eg ' ' or ',')
2874  * @retval     NULL  Error
2875  * @retval     cvec  Vector of strings. Free with cvec_free()
2876  * @code
2877  *    cvec   *cvv;
2878  *    cg_var *cv = NULL;
2879  *    if ((cvv = yang_arg2cvec(ys, " ")) == NULL)
2880  *       goto err;
2881  *    while ((cv = cvec_each(cvv, cv)) != NULL)
2882  *         ...cv_string_get(cv);
2883  *    cvec_free(cvv);
2884  * @endcode
2885  * @note must free return value after use w cvec_free
2886  */
2887 cvec *
yang_arg2cvec(yang_stmt * ys,char * delim)2888 yang_arg2cvec(yang_stmt *ys,
2889 	      char      *delim)
2890 {
2891     char  **vec = NULL;
2892     int     i;
2893     int     nvec;
2894     cvec   *cvv = NULL;
2895     cg_var *cv;
2896 
2897     if ((vec = clicon_strsep(ys->ys_argument, " ", &nvec)) == NULL)
2898 	goto done;
2899     if ((cvv = cvec_new(nvec)) == NULL){
2900 	clicon_err(OE_YANG, errno, "cvec_new");
2901 	goto done;
2902     }
2903     for (i = 0; i < nvec; i++) {
2904 	cv = cvec_i(cvv, i);
2905 	cv_type_set(cv, CGV_STRING);
2906 	if ((cv_string_set(cv, vec[i])) == NULL){
2907 	    clicon_err(OE_YANG, errno, "cv_string_set");
2908 	    cvv = NULL;
2909 	    goto done;
2910 	}
2911     }
2912  done:
2913     if (vec)
2914 	free(vec);
2915     return cvv;
2916 }
2917 
2918 /*! Check if yang is subject to generated cli GT_HIDE boolean
2919  * The yang should be:
2920  * 1) a non-presence container
2921  * 2) parent of a (single) list XXX: or could multiple lists work?
2922  * 3) no other data node children
2923  * @retval   0   No, does not satisfy the GT_HIDE condition
2924  * @retval   1   Yes, satisfies the GT_HIDE condition
2925  * @see clixon-config.yang HIDE enumeration type
2926  */
2927 int
yang_container_cli_hide(yang_stmt * ys,enum genmodel_type gt)2928 yang_container_cli_hide(yang_stmt         *ys,
2929 			enum genmodel_type gt)
2930 {
2931     yang_stmt    *yc = NULL;
2932     int           i;
2933     enum rfc_6020 keyw;
2934 
2935     keyw = yang_keyword_get(ys);
2936     /* HIDE mode */
2937     if (gt != GT_HIDE)
2938 	return 0;
2939     /* A container */
2940     if (yang_keyword_get(ys) != Y_CONTAINER)
2941 	return 0;
2942     /* Non-presence */
2943     if (yang_find(ys, Y_PRESENCE, NULL) != NULL)
2944 	return 0;
2945     /* Ensure a single list child and no other data nodes */
2946     i = 0; /* Number of list nodes */
2947     while ((yc = yn_each(ys, yc)) != NULL) {
2948 	keyw = yang_keyword_get(yc);
2949 	/* case/choice could hide anything so disqualify those */
2950 	if (keyw == Y_CASE || keyw == Y_CHOICE)
2951 	    break;
2952 	if (!yang_datanode(yc)) /* Allowed, check next */
2953 	    continue;
2954 	if (keyw != Y_LIST) /* Another datanode than list */
2955 	    break;
2956 	if (i++>0) /* More than one list (or could this work?) */
2957 	    break;
2958     }
2959     if (yc != NULL) /* break from loop */
2960 	return 0;
2961     if (i != 1) /* List found */
2962 	return 0;
2963     return 1; /* Passed all tests: yes you can hide this keyword */
2964 }
2965 
2966 /*! Check if yang node yn has key-stmt as child which matches name
2967  *
2968  * The function looks at the LIST argument string (not actual children)
2969  * @param[in]  yn   Yang node with sub-statements (look for a key child)
2970  * @param[in]  name Check if this name (eg "b") is a key in the yang key statement
2971  *
2972  * @retval   -1     Error
2973  * @retval    0     No match
2974  * @retval    1     Yes match
2975  */
2976 int
yang_key_match(yang_stmt * yn,char * name)2977 yang_key_match(yang_stmt *yn,
2978 	       char      *name)
2979 {
2980     int        retval = -1;
2981     yang_stmt *ys = NULL;
2982     int        i;
2983     cvec      *cvv = NULL;
2984     cg_var    *cv;
2985 
2986     for (i=0; i<yn->ys_len; i++){
2987 	ys = yn->ys_stmt[i];
2988 	if (ys->ys_keyword == Y_KEY){
2989 	    if ((cvv = yang_arg2cvec(ys, " ")) == NULL)
2990 		goto done;
2991 	    cv = NULL;
2992 	    while ((cv = cvec_each(cvv, cv)) != NULL) {
2993 		if (strcmp(name, cv_string_get(cv)) == 0){
2994 		    retval = 1; /* match */
2995 		    goto done;
2996 		}
2997 	    }
2998 	    cvec_free(cvv);
2999 	    cvv = NULL;
3000 	}
3001     }
3002     retval = 0;
3003  done:
3004     if (cvv)
3005 	cvec_free(cvv);
3006     return retval;
3007 }
3008 
3009 /*! Set type cache for yang type
3010  * @param[in] rxmode  Kludge to know which regexp engine is used
3011  * @see yang_type_cache_regexp_set where cache is extended w compiled regexps
3012  */
3013 int
yang_type_cache_set(yang_stmt * ys,yang_stmt * resolved,int options,cvec * cvv,cvec * patterns,uint8_t fraction)3014 yang_type_cache_set(yang_stmt        *ys,
3015 		    yang_stmt        *resolved,
3016 		    int               options,
3017 		    cvec             *cvv,
3018 		    cvec             *patterns,
3019 		    uint8_t           fraction)
3020 {
3021     int              retval = -1;
3022     yang_type_cache *ycache;
3023 
3024     if (ys->ys_typecache != NULL){
3025 	clicon_err(OE_YANG, EEXIST, "yang type cache");
3026 	goto done;
3027     }
3028     if ((ys->ys_typecache = (yang_type_cache *)malloc(sizeof(*ycache))) == NULL){
3029 	clicon_err(OE_UNIX, errno, "malloc");
3030 	goto done;
3031     }
3032     ycache = ys->ys_typecache;
3033     memset(ycache, 0, sizeof(*ycache));
3034     ycache->yc_resolved  = resolved;
3035     ycache->yc_options  = options;
3036     if (cvv){
3037 	if ((ycache->yc_cvv = cvec_dup(cvv)) == NULL){
3038 	    clicon_err(OE_UNIX, errno, "cvec_dup");
3039 	    goto done;
3040 	}
3041     }
3042     if (patterns && (ycache->yc_patterns  = cvec_dup(patterns)) == NULL){
3043 	clicon_err(OE_UNIX, errno, "cvec_dup");
3044 	goto done;
3045     }
3046     ycache->yc_fraction  = fraction;
3047     retval = 0;
3048  done:
3049     return retval;
3050 }
3051 
3052 /*! Extend yang type cache with compiled regexps
3053  * Compiled Regexps are computed in validate code - after initial cache set
3054  * @param[in] regexps
3055  */
3056 int
yang_type_cache_regexp_set(yang_stmt * ytype,int rxmode,cvec * regexps)3057 yang_type_cache_regexp_set(yang_stmt *ytype,
3058 			   int        rxmode,
3059 			   cvec      *regexps)
3060 {
3061     int               retval = -1;
3062     yang_type_cache  *ycache;
3063 
3064     assert(regexps);
3065     assert(yang_keyword_get(ytype) == Y_TYPE);
3066     assert((ycache = ytype->ys_typecache) != NULL);
3067     assert(ycache->yc_regexps == NULL);
3068     ycache->yc_rxmode = rxmode;
3069     if ((ycache->yc_regexps  = cvec_dup(regexps)) == NULL){
3070 	clicon_err(OE_UNIX, errno, "cvec_dup");
3071 	goto done;
3072     }
3073     retval = 0;
3074  done:
3075     return retval;
3076 }
3077 
3078 /*! Get individual fields (direct/destructively) from yang type cache.
3079  * @param[out] patterns Initialized cvec of regexp patterns strings
3080  * @retval    -1        Error
3081  * @retval     0        No cache
3082  * @retval     1        OK
3083  */
3084 int
yang_type_cache_get(yang_stmt * ytype,yang_stmt ** resolved,int * options,cvec ** cvv,cvec * patterns,int * rxmode,cvec * regexps,uint8_t * fraction)3085 yang_type_cache_get(yang_stmt   *ytype,
3086 		    yang_stmt  **resolved,
3087 		    int         *options,
3088 		    cvec       **cvv,
3089 		    cvec        *patterns,
3090 		    int         *rxmode,
3091 		    cvec        *regexps,
3092 		    uint8_t     *fraction)
3093 {
3094     int              retval = -1;
3095     cg_var          *cv = NULL;
3096     yang_type_cache *ycache;
3097 
3098     ycache = ytype->ys_typecache;
3099     if (ycache == NULL){ /* No cache return 0 */
3100 	retval = 0;
3101 	goto done;
3102     }
3103     if (resolved)
3104 	*resolved = ycache->yc_resolved;
3105     if (options)
3106 	*options  = ycache->yc_options;
3107     if (cvv)
3108 	*cvv    = ycache->yc_cvv;
3109     if (patterns){
3110 	cv = NULL;
3111 	while ((cv = cvec_each(ycache->yc_patterns, cv)) != NULL)
3112 	    cvec_append_var(patterns, cv);
3113     }
3114     if (regexps){
3115 	cv = NULL;
3116 	while ((cv = cvec_each(ycache->yc_regexps, cv)) != NULL)
3117 	    cvec_append_var(regexps, cv);
3118     }
3119     if (rxmode)
3120 	*rxmode = ycache->yc_rxmode;
3121     if (fraction)
3122 	*fraction = ycache->yc_fraction;
3123     retval = 1; /* cache exists and is returned OK */
3124  done:
3125     return retval;
3126 }
3127 
3128 /*! Copy yang type cache
3129  */
3130 static int
yang_type_cache_cp(yang_stmt * ynew,yang_stmt * yold)3131 yang_type_cache_cp(yang_stmt *ynew,
3132 		   yang_stmt *yold)
3133 {
3134     int        retval = -1;
3135     int        options;
3136     cvec      *cvv;
3137     cvec      *patterns = NULL;
3138     uint8_t    fraction;
3139     yang_stmt *resolved;
3140     int        ret;
3141 
3142     if ((patterns = cvec_new(0)) == NULL){
3143 	clicon_err(OE_UNIX, errno, "cvec_new");
3144 	goto done;
3145     }
3146     /* Note, regexps are not copied since they are voids, if they were, they
3147      * could not be freed in a simple way since copies are made at augment/group
3148      */
3149     if ((ret = yang_type_cache_get(yold,
3150 				   &resolved, &options, &cvv, patterns, NULL, NULL, &fraction)) < 0)
3151 	goto done;
3152     if (ret == 1 &&
3153 	yang_type_cache_set(ynew, resolved, options, cvv, patterns, fraction) < 0)
3154 	goto done;
3155     retval = 0;
3156  done:
3157     if (patterns)
3158 	cvec_free(patterns);
3159     return retval;
3160 }
3161 
3162 /*! Free yang type cache
3163  */
3164 static int
yang_type_cache_free(yang_type_cache * ycache)3165 yang_type_cache_free(yang_type_cache *ycache)
3166 {
3167     cg_var *cv;
3168     void   *p;
3169 
3170     if (ycache->yc_cvv)
3171 	cvec_free(ycache->yc_cvv);
3172     if (ycache->yc_patterns)
3173 	cvec_free(ycache->yc_patterns);
3174     if (ycache->yc_regexps){
3175 	cv = NULL;
3176 	while ((cv = cvec_each(ycache->yc_regexps, cv)) != NULL){
3177 	    /* need to store mode since clicon_handle is not available */
3178 	    switch (ycache->yc_rxmode){
3179 	    case REGEXP_POSIX:
3180 		cligen_regex_posix_free(cv_void_get(cv));
3181 		if ((p = cv_void_get(cv)) != NULL){
3182 		    free(p);
3183 		    cv_void_set(cv, NULL);
3184 		}
3185 		break;
3186 	    case REGEXP_LIBXML2:
3187 		cligen_regex_libxml2_free(cv_void_get(cv));
3188 		/* Note, already freed in libxml2 case */
3189 		if ((p = cv_void_get(cv)) != NULL){
3190 		    cv_void_set(cv, NULL);
3191 		}
3192 		break;
3193 	    default:
3194 		break;
3195 	    }
3196 
3197 	}
3198 	cvec_free(ycache->yc_regexps);
3199     }
3200     free(ycache);
3201     return 0;
3202 }
3203 
3204 /*! Add a simple anydata-node
3205  *
3206  * One usecase is CLICON_YANG_UNKNOWN_ANYDATA when unknown data is treated as anydata
3207  * @param[in]  yp    Yang parent statement
3208  * @param[in]  name  Node name, will be copied
3209  * @retval     ys    OK
3210  * @retval     NULL  Error
3211  * @see ysp_add
3212  */
3213 yang_stmt *
yang_anydata_add(yang_stmt * yp,char * name0)3214 yang_anydata_add(yang_stmt *yp,
3215 		 char      *name0)
3216 {
3217     yang_stmt *ys = NULL;
3218     char      *name = NULL;
3219 
3220     if ((ys = ys_new(Y_ANYDATA)) == NULL)
3221 	goto done;
3222     if ((name = strdup(name0)) == NULL){
3223 	clicon_err(OE_UNIX, errno, "strdup");
3224 	goto done;
3225     }
3226     yang_argument_set(ys, name);
3227     if (yn_insert(yp, ys) < 0){ /* Insert into hierarchy */
3228 	ys = NULL;
3229 	goto done;
3230     }
3231  done:
3232     return ys;
3233 }
3234 
3235 #ifdef XML_EXPLICIT_INDEX
3236 /*! Mark element as search_index in list
3237  * @retval     0   OK
3238  * @retval    -1   Error
3239  */
3240 int
yang_list_index_add(yang_stmt * ys)3241 yang_list_index_add(yang_stmt *ys)
3242 {
3243     int        retval = -1;
3244     yang_stmt *yp;
3245 
3246     if ((yp = yang_parent_get(ys)) == NULL ||
3247 	yang_keyword_get(yp) != Y_LIST){
3248 	clicon_log(LOG_WARNING, "search_index should in a list");
3249 	goto ok;
3250     }
3251     yang_flag_set(ys, YANG_FLAG_INDEX);
3252  ok:
3253     retval = 0;
3254    // done:
3255     return retval;
3256 }
3257 
3258 /*! Callback for yang clixon search_index extension
3259  *
3260  * @param[in] h    Clixon handle
3261  * @param[in] yext Yang node of extension
3262  * @param[in] ys   Yang node of (unknown) statement belonging to extension
3263  * @retval     0   OK (warnings may appear)
3264  * @retval    -1   Error
3265  */
3266 int
yang_search_index_extension(clicon_handle h,yang_stmt * yext,yang_stmt * ys)3267 yang_search_index_extension(clicon_handle h,
3268 			    yang_stmt    *yext,
3269 			    yang_stmt    *ys)
3270 {
3271     int        retval = -1;
3272     char      *extname;
3273     char      *modname;
3274     yang_stmt *ymod;
3275     yang_stmt *yp;
3276 
3277     ymod = ys_module(yext);
3278     modname = yang_argument_get(ymod);
3279     extname = yang_argument_get(yext);
3280     if (strcmp(modname, "clixon-config") != 0 || strcmp(extname, "search_index") != 0)
3281 	goto ok;
3282     clicon_debug(1, "%s Enabled extension:%s:%s", __FUNCTION__, modname, extname);
3283     yp = yang_parent_get(ys);
3284     if (yang_list_index_add(yp) < 0)
3285 	goto done;
3286  ok:
3287     retval = 0;
3288  done:
3289     return retval;
3290 }
3291 
3292 #endif /* XML_EXPLICIT_INDEX */
3293