diff --git a/README.md b/README.md index cf539327..47b72648 100644 --- a/README.md +++ b/README.md @@ -99,11 +99,14 @@ However, the following YANG syntax modules are not implemented (reference to RFC - deviation (7.20.3) - action (7.15) - augment in a uses sub-clause (7.17) (module-level augment is implemented) +- require-instance +- instance-identifier type - status (7.21.2) -- extension (7.19) +- extension (7.19) supported syntactically, but no hooks/plugins for extenstions - YIN (13) - Yang extended Xpath functions: re-match(), deref)(), derived-from(), derived-from-or-self(), enum-value(), bit-is-set() (10.2-10.6) - Default values on leaf-lists are not supported (7.7.2) +- instance-identifier type ### Yang patterns Yang type patterns use regexps defined in [W3C XML XSD](http://www.w3.org/TR/2004/REC-xmlschema-2-20041028). XSD regexp:s are diff --git a/apps/cli/cli_common.c b/apps/cli/cli_common.c index 303942a5..af24ea9c 100644 --- a/apps/cli/cli_common.c +++ b/apps/cli/cli_common.c @@ -184,6 +184,40 @@ cli_signal_flush(clicon_handle h) cli_signal_block (h); } +/*! Transform data + * Add next-last cvv (resolved variable) as body to xml bottom for leaf and + * leaf-list. + * There may be some translation necessary. + */ +static int +dbxml_body(cxobj *xbot, + yang_stmt *ybot, + cvec *cvv) +{ + int retval = -1; + char *str = NULL; + cxobj *xb; + cg_var *cval; + int len; + + len = cvec_len(cvv); + cval = cvec_i(cvv, len-1); + if ((str = cv2str_dup(cval)) == NULL){ + clicon_err(OE_UNIX, errno, "cv2str_dup"); + goto done; + } + if ((xb = xml_new("body", xbot, NULL)) == NULL) + goto done; + xml_type_set(xb, CX_BODY); + if (xml_value_set(xb, str) < 0) + goto done; + retval = 0; + done: + if (str) + free(str); + return retval; +} + /*! Modify xml datastore from a callback using xml key format strings * @param[in] h Clicon handle * @param[in] cvv Vector of cli string and instantiated variables @@ -206,11 +240,11 @@ cli_dbxml(clicon_handle h, enum operation_type op) { int retval = -1; - char *str = NULL; + // char *str = NULL; char *api_path_fmt; /* xml key format */ char *api_path = NULL; /* xml key */ - cg_var *cval; - int len; + // cg_var *cval; + // int len; cg_var *arg; cbuf *cb = NULL; yang_stmt *yspec; @@ -218,7 +252,7 @@ cli_dbxml(clicon_handle h, yang_stmt *y = NULL; /* yang spec of xpath */ cxobj *xtop = NULL; /* xpath root */ cxobj *xa; /* attribute */ - cxobj *xb; /* body */ + // cxobj *xb; /* body */ if (cvec_len(argv) != 1){ clicon_err(OE_PLUGIN, 0, "Requires one element to be xml key format string"); @@ -241,22 +275,12 @@ cli_dbxml(clicon_handle h, if ((xa = xml_new("operation", xbot, NULL)) == NULL) goto done; xml_type_set(xa, CX_ATTR); - if (xml_value_set(xa, xml_operation2str(op)) < 0) + if (xml_value_set(xa, xml_operation2str(op)) < 0) goto done; if (yang_keyword_get(y) != Y_LIST && yang_keyword_get(y) != Y_LEAF_LIST){ - len = cvec_len(cvv); - if (len > 1){ - cval = cvec_i(cvv, len-1); - if ((str = cv2str_dup(cval)) == NULL){ - clicon_err(OE_UNIX, errno, "cv2str_dup"); - goto done; - } - if ((xb = xml_new("body", xbot, NULL)) == NULL) - goto done; - xml_type_set(xb, CX_BODY); - if (xml_value_set(xb, str) < 0) - goto done; - } + if (cvec_len(cvv) > 1 && + dbxml_body(xbot, y, cvv) < 0) + goto done; } if ((cb = cbuf_new()) == NULL){ clicon_err(OE_XML, errno, "cbuf_new"); @@ -274,8 +298,6 @@ cli_dbxml(clicon_handle h, done: if (cb) cbuf_free(cb); - if (str) - free(str); if (api_path) free(api_path); if (xtop) diff --git a/apps/cli/cli_generate.c b/apps/cli/cli_generate.c index 5a0c4cf6..1d9400d3 100644 --- a/apps/cli/cli_generate.c +++ b/apps/cli/cli_generate.c @@ -530,7 +530,7 @@ yang2cli_var(clicon_handle h, cbuf *cb) { int retval = -1; - char *origtype; + char *origtype = NULL; yang_stmt *yrestype; /* resolved type */ char *restype; /* resolved type */ cvec *cvv = NULL; @@ -596,6 +596,8 @@ yang2cli_var(clicon_handle h, } retval = 0; done: + if (origtype) + free(origtype); if (patterns) cvec_free(patterns); return retval; diff --git a/include/clixon_custom.h b/include/clixon_custom.h index 1127dfce..b36a54ab 100644 --- a/include/clixon_custom.h +++ b/include/clixon_custom.h @@ -48,3 +48,9 @@ */ #define USE_NETCONF_NS_AS_DEFAULT +/* Use modulename:id instead of prefix:id in derived identityref list + * Modulenames are global/canonical but prefixes are not. + * Experimental since there is some mapping between prefixes and module names + * that needs to be done + */ +#undef USE_IDREF_LIST_MODULE diff --git a/lib/clixon/clixon_xml_map.h b/lib/clixon/clixon_xml_map.h index 0b3b9842..6730b02d 100644 --- a/lib/clixon/clixon_xml_map.h +++ b/lib/clixon/clixon_xml_map.h @@ -44,6 +44,7 @@ typedef enum yang_class yang_class; /* * Prototypes */ +int isxmlns(cxobj *x); int xml2txt(FILE *f, cxobj *x, int level); int xml2cli(FILE *f, cxobj *x, char *prepend, enum genmodel_type gt); int xml_yang_root(cxobj *x, cxobj **xr); diff --git a/lib/clixon/clixon_yang.h b/lib/clixon/clixon_yang.h index 1c8c3e7b..c703f4f0 100644 --- a/lib/clixon/clixon_yang.h +++ b/lib/clixon/clixon_yang.h @@ -164,8 +164,6 @@ yang_stmt *ys_dup(yang_stmt *old); int yn_insert(yang_stmt *ys_parent, yang_stmt *ys_child); yang_stmt *yn_each(yang_stmt *yn, yang_stmt *ys); char *yang_key2str(int keyword); -char *yarg_prefix(yang_stmt *ys); -char *yarg_id(yang_stmt *ys); int ys_module_by_xml(yang_stmt *ysp, struct xml *xt, yang_stmt **ymodp); yang_stmt *ys_module(yang_stmt *ys); yang_stmt *ys_real_module(yang_stmt *ys); diff --git a/lib/src/clixon_datastore_write.c b/lib/src/clixon_datastore_write.c index 594a9305..9689ed4e 100644 --- a/lib/src/clixon_datastore_write.c +++ b/lib/src/clixon_datastore_write.c @@ -83,6 +83,45 @@ #include "clixon_datastore_read.h" #include "clixon_datastore_tree.h" +/*! Replace all xmlns attributes in x0 with xmlns attributes in x1 + * This is an embryo of code to actually check if namespace binding is canonical + * and if it is not, either return error or transform to canonical. + * "Canonical" meaning comply to the yang module prefixes. + * The current code does not really do anything useful + */ +static int +replace_xmlns(cxobj *x0, + cxobj *x1) +{ + int retval = -1; + cxobj *x = NULL; + cxobj *xcopy; + int i; + + for (i=0; i: which is the format of the derived + * identityref list associated with the base identities. + */ + /* Get namespace (of idref) from xml */ + if (xml2ns(xt, prefix, &namespace) < 0) + goto done; + yspec = ys_spec(ys); + /* Get module of that namespace */ + if ((ymod = yang_find_module_by_namespace(yspec, namespace)) == NULL){ + clicon_err(OE_YANG, ENOENT, "No module found"); + goto done; + } + cprintf(cb, "%s:%s", yang_argument_get(ymod), id); + } +#else +#ifdef USE_IDREF_LIST_MODULE + { + yang_stmt *ymod; + /* idref from prefix:id to module:id */ + if (prefix == NULL) + ymod = ys_module(ys); + else /* from prefix to name */ + ymod = yang_find_module_by_prefix(ys, prefix); + if (ymod == NULL){ + cprintf(cberr, "Identityref validation failed, %s not derived from %s", + node, yang_argument_get(ybaseid)); + if (netconf_operation_failed_xml(xret, "application", cbuf_get(cberr)) < 0) + goto done; + goto fail; + } + cprintf(cb, "%s:%s", yang_argument_get(ymod), id); + } +#else + if (prefix == NULL) + cprintf(cb, "%s:%s", yang_find_myprefix(ys), id); + else + cprintf(cb, "%s:%s", prefix, id); +#endif +#endif + idref = cbuf_get(cb); /* Here check if node is in the derived node list of the base identity * The derived node list is a cvec computed XXX */ - if (cvec_find(yang_cvec_get(ybaseid), node) == NULL){ - if ((cb2 = cbuf_new()) == NULL){ - clicon_err(OE_UNIX, errno, "cbuf_new"); - goto done; - } - cprintf(cb2, "Identityref validation failed, %s not derived from %s", + if (cvec_find(yang_cvec_get(ybaseid), idref) == NULL){ + cprintf(cberr, "Identityref validation failed, %s not derived from %s", node, yang_argument_get(ybaseid)); - if (netconf_operation_failed_xml(xret, "application", cbuf_get(cb2)) < 0) + if (netconf_operation_failed_xml(xret, "application", cbuf_get(cberr)) < 0) goto done; goto fail; } retval = 1; done: + if (cberr) + cbuf_free(cberr); if (cb) cbuf_free(cb); - if (cb2) - cbuf_free(cb2); + if (id) + free(id); + if (prefix) + free(prefix); return retval; fail: retval = 0; diff --git a/lib/src/clixon_yang.c b/lib/src/clixon_yang.c index 3e2cff9e..656c889e 100644 --- a/lib/src/clixon_yang.c +++ b/lib/src/clixon_yang.c @@ -1102,44 +1102,6 @@ ys_spec(yang_stmt *ys) return (yang_stmt*)ys; } -/* Assume argument is id on the type: <[prefix:]id>, return 'id' - * Just return string from id - * @param[in] ys A yang statement - * @retval NULL No id (argument is NULL) - * @retval id Pointer to identifier - * @see yarg_prefix - */ -char* -yarg_id(yang_stmt *ys) -{ - char *id; - - if ((id = strchr(ys->ys_argument, ':')) == NULL) - id = ys->ys_argument; - else - id++; - return id; -} - -/*! Assume argument is id on the type: <[prefix:]id>, return 'prefix' - * @param[in] ys A yang statement - * @retval NULL No prefix - * @retval prefix Malloced string that needs to be freed by caller. - * @see yarg_id - */ -char* -yarg_prefix(yang_stmt *ys) -{ - char *id; - char *prefix = NULL; - - if ((id = strchr(ys->ys_argument, ':')) != NULL){ - prefix = strdup(ys->ys_argument); - prefix[id-ys->ys_argument] = '\0'; - } - return prefix; -} - /*! Given a yang statement and a prefix, return yang module to that relative prefix * Note, not the other module but the proxy import statement only * @param[in] ys A yang statement @@ -1333,8 +1295,8 @@ yang_print_cbuf(cbuf *cb, * 4. Check if leaf is part of list, if key exists mark leaf as key/unique * XXX: extend type search * + * @param[in] h Clicon handle * @param[in] ys The yang statement to populate. - * @param[in] arg A void argument not used * @retval 0 OK * @retval -1 Error with clicon_err called */ @@ -1352,17 +1314,17 @@ ys_populate_leaf(clicon_handle h, char *reason = NULL; yang_stmt *yrestype; /* resolved type */ char *restype; /* resolved type */ - char *type; /* original type */ + char *origtype=NULL; /* original type */ uint8_t fraction_digits; int options = 0x0; yparent = ys->ys_parent; /* Find parent: list/container */ /* 1. Find type specification and set cv type accordingly */ - if (yang_type_get(ys, &type, &yrestype, &options, NULL, NULL, NULL, &fraction_digits) + if (yang_type_get(ys, &origtype, &yrestype, &options, NULL, NULL, NULL, &fraction_digits) < 0) goto done; restype = yrestype?yrestype->ys_argument:NULL; - if (clicon_type2cv(type, restype, ys, &cvtype) < 0) /* This handles non-resolved also */ + if (clicon_type2cv(origtype, restype, ys, &cvtype) < 0) /* This handles non-resolved also */ goto done; /* 2. Create the CV using cvtype and name it */ if ((cv = cv_new(cvtype)) == NULL){ @@ -1402,11 +1364,17 @@ ys_populate_leaf(clicon_handle h, ys->ys_cv = cv; retval = 0; done: + if (origtype) + free(origtype); if (cv && retval < 0) cv_free(cv); return retval; } +/*! Populate list yang statement + * @param[in] h Clicon handle + * @param[in] ys The yang statement (type) to populate. + */ static int ys_populate_list(clicon_handle h, yang_stmt *ys) @@ -1505,6 +1473,8 @@ range_parse(yang_stmt *ys, /*! Populate string built-in range statement * * Create cvec variables "range_min" and "range_max". Assume parent is type. + * @param[in] h Clicon handle + * @param[in] ys The yang statement (range) to populate. * Actually: bound[..bound] (| bound[..bound])* * where bound is integer, decimal or keywords 'min' or 'max. * RFC 7950 9.2.4: @@ -1519,10 +1489,10 @@ ys_populate_range(clicon_handle h, yang_stmt *ys) { int retval = -1; - yang_stmt *yparent; /* type */ - char *origtype; /* orig type */ - yang_stmt *yrestype; /* resolved type */ - char *restype; /* resolved type */ + yang_stmt *yparent; /* type */ + char *origtype = NULL; /* orig type */ + yang_stmt *yrestype; /* resolved type */ + char *restype; /* resolved type */ int options = 0x0; uint8_t fraction_digits; enum cv_type cvtype = CGV_ERR; @@ -1536,7 +1506,8 @@ ys_populate_range(clicon_handle h, &options, NULL, NULL, NULL, &fraction_digits) < 0) goto done; restype = yrestype?yrestype->ys_argument:NULL; - origtype = yarg_id((yang_stmt*)yparent); + if (nodeid_split(yang_argument_get(yparent), NULL, &origtype) < 0) + goto done; /* This handles non-resolved also */ if (clicon_type2cv(origtype, restype, ys, &cvtype) < 0) goto done; @@ -1548,15 +1519,21 @@ ys_populate_range(clicon_handle h, goto done; retval = 0; done: + if (origtype) + free(origtype); return retval; } /*! Populate integer built-in length statement * * Create cvec variables "range_min" and "range_max". Assume parent is type. + * @param[in] h Clicon handle + * @param[in] ys The yang statement (length) to populate. + * * Actually: len[..len] (| len[..len])* - * len is unsigned integer or keywords 'min' or 'max. - * RFC 7950 9.4.4 + * len is unsigned integer or keywords 'min' or 'max' + * + * From RFC 7950 Sec 9.4.4: * A length range consists of an explicit value, or a lower bound, two * consecutive dots "..", and an upper bound. Multiple values or ranges * can be given, separated by "|". Length-restricting values MUST NOT @@ -1586,8 +1563,8 @@ ys_populate_length(clicon_handle h, /*! Sanity check yang type statement * XXX: Replace with generic parent/child type-check + * @param[in] h Clicon handle * @param[in] ys The yang statement (type) to populate. - * @ */ static int ys_populate_type(clicon_handle h, @@ -1620,12 +1597,15 @@ ys_populate_type(clicon_handle h, return retval; } -/*! Sanity check yang identity statement recursively +/*! Sanity check yang identity statement recursively and create derived id list * - * Find base identities if any and add this identity to derived list. + * Find base identities if any and add this identity to derived identity list. * Do this recursively - * @param[in] ys The yang identity to populate. - * @param[in] arg If set contains a derived identifier + * The derived identity list is a list of : pairs. Prefixes cannot + * be used since they are local in scope. + * @param[in] h Clicon handle + * @param[in] ys The yang identity to populate. + * @param[in] idref If set contains the derived identifier(NULL on top call) * @see validate_identityref which in runtime validates actual values */ static int @@ -1636,28 +1616,40 @@ ys_populate_identity(clicon_handle h, int retval = -1; yang_stmt *yc = NULL; yang_stmt *ybaseid; + // yang_stmt *ymod; cg_var *cv; - char *derid; char *baseid; char *prefix = NULL; + char *id = NULL; cbuf *cb = NULL; - char *p; + /* Top-call (no recursion) create idref + * The idref is (here) in "canonical form": : + */ if (idref == NULL){ /* Create derived identity through prefix:id if not recursively called*/ - derid = ys->ys_argument; /* derived id */ - if ((prefix = yarg_prefix(ys)) == NULL){ - if ((p = yang_find_myprefix(ys)) != NULL) - prefix = strdup(yang_find_myprefix(ys)); - } if ((cb = cbuf_new()) == NULL){ clicon_err(OE_UNIX, errno, "cbuf_new"); goto done; } - if (prefix) - cprintf(cb, "%s:%s", prefix, derid); - else - cprintf(cb, "%s", derid); +#if 0 /* Use module:id instead of prefix:id in derived list */ + if (nodeid_split(yang_argument_get(ys), &prefix, &id) < 0) + goto done; + if ((ymod = ys_module(ys)) == NULL){ + clicon_err(OE_YANG, ENOENT, "No module found"); + goto done; + } + cprintf(cb, "%s:%s", yang_argument_get(ymod), id); +#else + { + if (nodeid_split(yang_argument_get(ys), &prefix, &id) < 0) + goto done; + if (prefix) + cprintf(cb, "%s:%s", prefix, id); + else + cprintf(cb, "%s:%s", yang_find_myprefix(ys), id); + } +#endif idref = cbuf_get(cb); } /* Iterate through all base statements and check the base identity exists @@ -1667,9 +1659,9 @@ ys_populate_identity(clicon_handle h, while ((yc = yn_each(ys, yc)) != NULL) { if (yc->ys_keyword != Y_BASE) continue; - baseid = yc->ys_argument; + baseid = yang_argument_get(yc); /* on the form: prefix:id */ if (((ybaseid = yang_find_identity(ys, baseid))) == NULL){ - clicon_err(OE_YANG, 0, "No such identity: %s", baseid); + clicon_err(OE_YANG, ENOENT, "No such identity: %s", baseid); goto done; } // continue; /* root identity */ @@ -1696,6 +1688,8 @@ ys_populate_identity(clicon_handle h, done: if (prefix) free(prefix); + if (id) + free(id); if (cb) cbuf_free(cb); return retval; @@ -1730,8 +1724,8 @@ if_feature(yang_stmt *yspec, /*! Populate yang feature statement - set cv to 1 if enabled * - * @param[in] ys Feature yang statement to populate. * @param[in] h Clicon handle + * @param[in] ys Feature yang statement to populate. */ static int ys_populate_feature(clicon_handle h, @@ -1792,6 +1786,8 @@ ys_populate_feature(clicon_handle h, } /*! Populate the unique statement with a cvec + * @param[in] h Clicon handle + * @param[in] ys The yang statement (unique) to populate. */ static int ys_populate_unique(clicon_handle h, @@ -1805,6 +1801,8 @@ ys_populate_unique(clicon_handle h, } /*! Populate unknown node with extension + * @param[in] h Clicon handle + * @param[in] ys The yang statement (unknown) to populate. */ static int ys_populate_unknown(clicon_handle h, @@ -1815,19 +1813,19 @@ ys_populate_unknown(clicon_handle h, char *reason = NULL; yang_stmt *ymod; char *prefix = NULL; - char *name; + char *id = NULL; char *extra; if ((extra = ys->ys_extra) == NULL) goto ok; /* Find extension, if found, store it as unknown, if not, break for error */ - prefix = yarg_prefix(ys); /* And this its prefix */ - name = yarg_id(ys); /* This is the type to resolve */ + if (nodeid_split(yang_argument_get(ys), &prefix, &id) < 0) + goto done; if ((ymod = yang_find_module_by_prefix(ys, prefix)) == NULL) goto ok; /* shouldnt happen */ - if (yang_find(ymod, Y_EXTENSION, name) == NULL){ - clicon_err(OE_YANG, errno, "Extension %s:%s not found", prefix, name); + if (yang_find(ymod, Y_EXTENSION, id) == NULL){ + clicon_err(OE_YANG, errno, "Extension %s:%s not found", prefix, id); goto done; } if ((ys->ys_cv = cv_new(CGV_STRING)) == NULL){ @@ -1847,13 +1845,15 @@ ys_populate_unknown(clicon_handle h, done: if (prefix) free(prefix); + if (id) + free(id); return retval; } /*! Populate with cligen-variables, default values, etc. Sanity checks on complete tree. * * @param[in] ys Yang statement - * @param[in] h Clicon handle + * @param[in] arg Argument - in effect Clicon handle * Preferably run this command using yang_apply * Done in 2nd pass after complete parsing to be sure to have a complete * parse-tree @@ -2150,8 +2150,8 @@ yang_expand_grouping(yang_stmt *yn) int glen; int i; int j; - char *name; - char *prefix; + char *id = NULL; + char *prefix = NULL; size_t size; /* Cannot use yang_apply here since child-list is modified (is destructive) */ @@ -2161,14 +2161,18 @@ yang_expand_grouping(yang_stmt *yn) switch(ys->ys_keyword){ case Y_USES: /* Split argument into prefix and name */ - name = yarg_id(ys); /* This is uses/grouping name to resolve */ - prefix = yarg_prefix(ys); /* And this its prefix */ - if (ys_grouping_resolve(ys, prefix, name, &ygrouping) < 0) + if (nodeid_split(yang_argument_get(ys), &prefix, &id) < 0) + goto done; + if (ys_grouping_resolve(ys, prefix, id, &ygrouping) < 0) goto done; if (prefix){ free(prefix); prefix = NULL; } + if (id){ + free(id); + id = NULL; + } if (ygrouping == NULL){ clicon_log(LOG_NOTICE, "%s: Yang error : grouping \"%s\" not found in module \"%s\"", __FUNCTION__, ys->ys_argument, ys_module(ys)->ys_argument); @@ -2258,6 +2262,10 @@ yang_expand_grouping(yang_stmt *yn) } retval = 0; done: + if (prefix) + free(prefix); + if (id) + free(id); return retval; } diff --git a/lib/src/clixon_yang_internal.h b/lib/src/clixon_yang_internal.h index 12edd24c..665fb512 100644 --- a/lib/src/clixon_yang_internal.h +++ b/lib/src/clixon_yang_internal.h @@ -96,7 +96,8 @@ struct yang_stmt{ cvec *ys_cvec; /* List of stmt-specific variables Y_RANGE: range_min, range_max Y_LIST: vector of keys - Y_TYPE & identity: store all derived types + Y_TYPE & identity: store all derived + types as : list */ yang_type_cache *ys_typecache; /* If ys_keyword==Y_TYPE, cache all typedef data except unions */ int _ys_vector_i; /* internal use: yn_each */ diff --git a/lib/src/clixon_yang_type.c b/lib/src/clixon_yang_type.c index 36818ecd..b665dca3 100644 --- a/lib/src/clixon_yang_type.c +++ b/lib/src/clixon_yang_type.c @@ -1058,7 +1058,7 @@ ys_cv_validate(clicon_handle h, cvec *patterns = NULL; cvec *regexps = NULL; enum cv_type cvtype; - char *type; /* orig type */ + char *origtype = NULL; /* orig type */ yang_stmt *yrestype; /* resolved type */ char *restype; uint8_t fraction = 0; @@ -1081,13 +1081,13 @@ ys_cv_validate(clicon_handle h, clicon_err(OE_UNIX, errno, "cvec_new"); goto done; } - if (yang_type_get(ys, &type, &yrestype, + if (yang_type_get(ys, &origtype, &yrestype, &options, &cvv, patterns, regexps, &fraction) < 0) goto done; restype = yrestype?yrestype->ys_argument:NULL; - if (clicon_type2cv(type, restype, ys, &cvtype) < 0) + if (clicon_type2cv(origtype, restype, ys, &cvtype) < 0) goto done; if (cv_type_get(ycv) != cvtype){ @@ -1104,7 +1104,7 @@ ys_cv_validate(clicon_handle h, if (restype && strcmp(restype, "union") == 0){ assert(cvtype == CGV_REST); val = cv_string_get(cv); - if ((retval2 = ys_cv_validate_union(h, ys, reason, yrestype, type, val)) < 0) + if ((retval2 = ys_cv_validate_union(h, ys, reason, yrestype, origtype, val)) < 0) goto done; retval = retval2; /* invalid (0) with latest reason or valid 1 */ } @@ -1127,6 +1127,8 @@ ys_cv_validate(clicon_handle h, goto done; } done: + if (origtype) + free(origtype); if (regexps) cvec_free(regexps); if (patterns) @@ -1165,48 +1167,43 @@ ys_typedef_up(yang_stmt *ys) } /*! Find identity yang-stmt - This is a sanity check of base identity of identity-ref and for identity - statements when parsing. - - Return true if node is identityref and is derived from identity_name - The derived-from() function returns true if the (first) node (in - document order in the argument "nodes") is a node of type identityref, - and its value is an identity that is derived from the identity - "identity-name" defined in the YANG module "module-name"; otherwise - it returns false. - - Valid values for an identityref are any identities derived from the - identityref's base identity. - 1. (base) identity must exist (be found). This is a sanity check - of the specification and also necessary for identity statements. - (This is what is done here) - 2. Check if a given node has value derived from base identity. This is - a run-time check necessary when validating eg netconf. - (This is validation) - 3. Find all valid derived identities from a identityref base identity. - (This is for cli generation) - * @param[in] ys Yang spec of id statement - * @param[in] identity Identity string -check if it exists - * @retval 0 OK - * @see validate_identityref for (2) above + * This is a sanity check of base identity of identity-ref and for identity + * statements when parsing. + * + * Return true if node is identityref and is derived from identity_name + * The derived-from() function returns true if the (first) node (in + * document order in the argument "nodes") is a node of type identityref, + * and its value is an identity that is derived from the identity + * "identity-name" defined in the YANG module "module-name"; otherwise + * it returns false. + * + * Valid values for an identityref are any identities derived from the + * identityref's base identity. + * 1. (base) identity must exist (be found). This is a sanity check + * of the specification and also necessary for identity statements. + * (This is what is done here) + * 2. Check if a given node has value derived from base identity. This is + * a run-time check necessary when validating eg netconf. + * (This is validation) + * 3. Find all valid derived identities from a identityref base identity. + * (This is for cli generation) + * @param[in] ys Yang spec of id statement + * @param[in] identity Identity string -check if it exists + * @retval 0 OK + * @see validate_identityref for (2) above */ yang_stmt * yang_find_identity(yang_stmt *ys, char *identity) { - char *id; + char *id = NULL; char *prefix = NULL; yang_stmt *ymodule; yang_stmt *yid = NULL; yang_stmt *yn; - if ((id = strchr(identity, ':')) == NULL) - id = identity; - else{ - prefix = strdup(identity); - prefix[id-identity] = '\0'; - id++; - } + if (nodeid_split(identity, &prefix, &id) < 0) + goto done; /* No, now check if identityref is derived from base */ if (prefix){ /* Go to top and find import that matches */ if ((ymodule = yang_find_module_by_prefix(ys, prefix)) == NULL) @@ -1231,6 +1228,8 @@ yang_find_identity(yang_stmt *ys, } } done: + if (id) + free(id); if (prefix) free(prefix); return yid; @@ -1334,7 +1333,7 @@ yang_type_resolve(yang_stmt *yorig, { yang_stmt *rytypedef = NULL; /* Resolved typedef of ytype */ yang_stmt *rytype; /* Resolved type of ytype */ - char *type; + char *type = NULL; char *prefix = NULL; int retval = -1; yang_stmt *yn; @@ -1343,8 +1342,9 @@ yang_type_resolve(yang_stmt *yorig, if (options) *options = 0x0; *yrestype = NULL; /* Initialization of resolved type that may not be necessary */ - type = yarg_id(ytype); /* This is the type to resolve */ - prefix = yarg_prefix(ytype); /* And this its prefix */ + + if (nodeid_split(yang_argument_get(ytype), &prefix, &type) < 0) + goto done; /* Cache does not work for eg string length 32? */ if (ytype->ys_typecache != NULL){ if (yang_type_cache_get(ytype->ys_typecache, yrestype, @@ -1409,6 +1409,8 @@ yang_type_resolve(yang_stmt *yorig, done: if (prefix) free(prefix); + if (type) + free(type); return retval; } @@ -1432,7 +1434,7 @@ yang_type_resolve(yang_stmt *yorig, * printf("%d..%d\n", min , max); * @endcode * @param[in] ys yang-stmt, leaf or leaf-list - * @param[out] origtype original type may be derived or built-in + * @param[out] origtype original type may be derived or built-in (malloced) * @param[out] yrestype Resolved type. return built-in type or NULL. * @param[out] options Flags field of optional values, see YANG_OPTIONS_* * @param[out] cvv Cvec with min/max range or length. @@ -1465,19 +1467,23 @@ yang_type_get(yang_stmt *ys, { int retval = -1; yang_stmt *ytype; /* type */ - char *type; + char *type = NULL; if (options) *options = 0x0; /* Find mandatory type */ if ((ytype = yang_find(ys, Y_TYPE, NULL)) == NULL){ - clicon_err(OE_DB, 0, "mandatory type object is not found"); + clicon_err(OE_DB, ENOENT, "mandatory type object is not found"); goto done; } /* XXX: here we seem to have some problems if type is union */ - type = yarg_id(ytype); - if (origtype) - *origtype = type; + if (nodeid_split(yang_argument_get(ytype), NULL, &type) < 0) + goto done; + if (origtype && + (*origtype = strdup(type)) == NULL){ + clicon_err(OE_XML, errno, "stdup"); + goto done; + } if (yang_type_resolve(ys, ys, ytype, yrestype, options, cvv, patterns, regexps, fraction) < 0) goto done; @@ -1485,6 +1491,8 @@ yang_type_get(yang_stmt *ys, *yrestype?(*yrestype)->ys_argument:"null"); retval = 0; done: + if (type) + free(type); return retval; } @@ -1496,16 +1504,18 @@ yang_type2cv(yang_stmt *ys) { yang_stmt *yrestype; /* resolved type */ char *restype; /* resolved type */ - char *type; /* original type */ + char *origtype=NULL; /* original type */ enum cv_type cvtype = CGV_ERR; /* Find type specification */ - if (yang_type_get(ys, &type, &yrestype, NULL, NULL, NULL, NULL, NULL) + if (yang_type_get(ys, &origtype, &yrestype, NULL, NULL, NULL, NULL, NULL) < 0) goto done; restype = yrestype?yrestype->ys_argument:NULL; - if (clicon_type2cv(type, restype, ys, &cvtype) < 0) /* This handles non-resolved also */ + if (clicon_type2cv(origtype, restype, ys, &cvtype) < 0) /* This handles non-resolved also */ goto done; done: + if (origtype) + free(origtype); return cvtype; } diff --git a/test/test_identity.sh b/test/test_identity.sh index 81f956e5..b8005d97 100755 --- a/test/test_identity.sh +++ b/test/test_identity.sh @@ -226,7 +226,7 @@ new "Netconf set undefined acl-type" expecteof "$clixon_netconf -qf $cfg" 0 'xundefined]]>]]>' '^]]>]]>$' new "netconf validate fail" -expecteof "$clixon_netconf -qf $cfg" 0 "]]>]]>" '^applicationoperation-failederrorIdentityref validation failed, mc:undefined not derived from acl-base]]>]]>' +expecteof "$clixon_netconf -qf $cfg" 0 "]]>]]>" '^applicationoperation-failederrorIdentityref validation failed, undefined not derived from acl-base]]>]]>' new "netconf discard-changes" expecteof "$clixon_netconf -qf $cfg" 0 "]]>]]>" "^]]>]]>$"