diff --git a/CHANGELOG.md b/CHANGELOG.md index ea4a2db6..66185599 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,8 @@ # Clixon CHANGELOG -- Genearlized yang type resolution. +- Restricted yang (sub)module file match to match RFC6020 exactly + +- Generalized yang type resolution to all included (sub)modules not just the topmost - Generic map_str2int generic mapping tables diff --git a/apps/cli/cli_common.c b/apps/cli/cli_common.c index 86fe558d..ac631765 100644 --- a/apps/cli/cli_common.c +++ b/apps/cli/cli_common.c @@ -644,6 +644,7 @@ compare_dbs(clicon_handle h, { cxobj *xc1 = NULL; /* running xml */ cxobj *xc2 = NULL; /* candidate xml */ + cxobj *xerr; int retval = -1; int astext; @@ -655,10 +656,18 @@ compare_dbs(clicon_handle h, astext = cv_int32_get(cvec_i(argv, 0)); else astext = 0; - if (clicon_rpc_get_config(h, "running", "/", 0, &xc1) < 0) + if (clicon_rpc_get_config(h, "running", "/", &xc1) < 0) goto done; - if (clicon_rpc_get_config(h, "candidate", "/", 0, &xc2) < 0) + if ((xerr = xpath_first(xc1, "/rpc-error")) != NULL){ + clicon_rpc_generate_error(xerr); goto done; + } + if (clicon_rpc_get_config(h, "candidate", "/", &xc2) < 0) + goto done; + if ((xerr = xpath_first(xc2, "/rpc-error")) != NULL){ + clicon_rpc_generate_error(xerr); + goto done; + } if (compare_xmls(xc1, xc2, astext) < 0) /* astext? */ goto done; retval = 0; @@ -800,6 +809,7 @@ save_config_file(clicon_handle h, char *dbstr; char *varstr; cxobj *xt = NULL; + cxobj *xerr; FILE *f = NULL; if (cvec_len(argv) != 2){ @@ -823,8 +833,12 @@ save_config_file(clicon_handle h, goto done; } filename = cv_string_get(cv); - if (clicon_rpc_get_config(h, dbstr,"/", 0, &xt) < 0) + if (clicon_rpc_get_config(h, dbstr,"/", &xt) < 0) goto done; + if ((xerr = xpath_first(xt, "/rpc-error")) != NULL){ + clicon_rpc_generate_error(xerr); + goto done; + } if ((f = fopen(filename, "wb")) == NULL){ clicon_err(OE_CFG, errno, "Creating file %s", filename); goto done; @@ -1122,6 +1136,7 @@ cli_copy_config(clicon_handle h, char *tovar; cg_var *tocv; char *toname; + cxobj *xerr; if (cvec_len(argv) != 5){ clicon_err(OE_PLUGIN, 0, "%s: Requires four elements: ", __FUNCTION__); @@ -1162,8 +1177,12 @@ cli_copy_config(clicon_handle h, cprintf(cb, xpath, keyname, fromname); /* Get from object configuration and store in x1 */ - if (clicon_rpc_get_config(h, db, cbuf_get(cb), 0, &x1) < 0) + if (clicon_rpc_get_config(h, db, cbuf_get(cb), &x1) < 0) goto done; + if ((xerr = xpath_first(x1, "/rpc-error")) != NULL){ + clicon_rpc_generate_error(xerr); + goto done; + } /* Get to variable -> cv -> to name */ if ((tocv = cvec_find_var(cvv, tovar)) == NULL){ diff --git a/apps/cli/cli_show.c b/apps/cli/cli_show.c index 62a6ac3f..6240ac31 100644 --- a/apps/cli/cli_show.c +++ b/apps/cli/cli_show.c @@ -104,6 +104,7 @@ expand_dbvar(void *h, cxobj *xt = NULL; char *xpath = NULL; cxobj **xvec = NULL; + cxobj *xerr; size_t xlen = 0; cxobj *x; char *bodystr; @@ -140,8 +141,12 @@ expand_dbvar(void *h, if (api_path_fmt2xpath(api_path, cvv, &xpath) < 0) goto done; /* XXX read whole configuration, why not send xpath? */ - if (clicon_rpc_get_config(h, dbstr, "/", 0, &xt) < 0) + if (clicon_rpc_get_config(h, dbstr, "/", &xt) < 0) goto done; + if ((xerr = xpath_first(xt, "/rpc-error")) != NULL){ + clicon_rpc_generate_error(xerr); + goto done; + } /* One round to detect duplicates * XXX The code below would benefit from some cleanup */ @@ -379,6 +384,7 @@ cli_show_config(clicon_handle h, char *val = NULL; cxobj *xt = NULL; cxobj *xc; + cxobj *xerr; enum genmodel_type gt; if (cvec_len(argv) != 3 && cvec_len(argv) != 4){ @@ -426,8 +432,12 @@ cli_show_config(clicon_handle h, else cprintf(cbxpath, "%s", xpath); /* Get configuration from database */ - if (clicon_rpc_get_config(h, db, cbuf_get(cbxpath), 0, &xt) < 0) + if (clicon_rpc_get_config(h, db, cbuf_get(cbxpath), &xt) < 0) goto done; + if ((xerr = xpath_first(xt, "/rpc-error")) != NULL){ + clicon_rpc_generate_error(xerr); + goto done; + } /* Print configuration according to format */ switch (format){ case FORMAT_XML: @@ -487,6 +497,7 @@ show_conf_xpath(clicon_handle h, char *xpath; cg_var *cv; cxobj *xt = NULL; + cxobj *xerr; cxobj **xv = NULL; size_t xlen; int i; @@ -505,8 +516,12 @@ show_conf_xpath(clicon_handle h, } cv = cvec_find_var(cvv, "xpath"); xpath = cv_string_get(cv); - if (clicon_rpc_get_config(h, str, xpath, 0, &xt) < 0) + if (clicon_rpc_get_config(h, str, xpath, &xt) < 0) goto done; + if ((xerr = xpath_first(xt, "/rpc-error")) != NULL){ + clicon_rpc_generate_error(xerr); + goto done; + } if (xpath_vec(xt, xpath, &xv, &xlen) < 0) goto done; for (i=0; iout, "Status: %d %s\r\n", code, reason_phrase); FCGX_FPrintF(r->out, "Content-Type: application/yang-data+json\r\n\r\n"); diff --git a/datastore/text/Makefile.in b/datastore/text/Makefile.in index 79c97729..5cc95cb2 100644 --- a/datastore/text/Makefile.in +++ b/datastore/text/Makefile.in @@ -85,7 +85,7 @@ install: $(PLUGIN) install-include: uninstall: - rm -rf $(DESTDIR)$(clixon_LIBDIR)/xmldb/$(PLUGIN) + rm -rf $(DESTDIR)$(libdir)/xmldb/$(PLUGIN) TAGS: find . -name '*.[chyl]' -print | etags - diff --git a/example/routing_cli.c b/example/routing_cli.c index 0cfbdfe7..e2e67b2b 100644 --- a/example/routing_cli.c +++ b/example/routing_cli.c @@ -81,7 +81,7 @@ mycallback(clicon_handle h, cvec *cvv, cvec *argv) /* Show eth0 interfaces config using XPATH */ if (clicon_rpc_get_config(h, "running","/interfaces/interface[name=eth0]", - 0, &xret) < 0) + &xret) < 0) goto done; xml_print(stdout, xret); diff --git a/lib/clixon/clixon_proto_client.h b/lib/clixon/clixon_proto_client.h index bac31496..c19997d1 100644 --- a/lib/clixon/clixon_proto_client.h +++ b/lib/clixon/clixon_proto_client.h @@ -45,8 +45,7 @@ int clicon_rpc_msg(clicon_handle h, struct clicon_msg *msg, cxobj **xret0, int clicon_rpc_netconf(clicon_handle h, char *xmlst, cxobj **xret, int *sp); int clicon_rpc_netconf_xml(clicon_handle h, cxobj *xml, cxobj **xret, int *sp); int clicon_rpc_generate_error(cxobj *xerr); -int clicon_rpc_get_config(clicon_handle h, char *db, char *xpath, - int errmode, cxobj **xret); +int clicon_rpc_get_config(clicon_handle h, char *db, char *xpath, cxobj **xret); int clicon_rpc_edit_config(clicon_handle h, char *db, enum operation_type op, char *xml); int clicon_rpc_copy_config(clicon_handle h, char *db1, char *db2); diff --git a/lib/src/clixon_proto_client.c b/lib/src/clixon_proto_client.c index dfd50e1d..e0bc54eb 100644 --- a/lib/src/clixon_proto_client.c +++ b/lib/src/clixon_proto_client.c @@ -230,31 +230,33 @@ clicon_rpc_generate_error(cxobj *xerr) * @param[in] h CLICON handle * @param[in] db Name of database * @param[in] xpath XPath (or "") - * @param[in] errmode 0 if xml errors are returned as clicon_err - * 1 if xml errors are in xt and return 0. - * @param[out] xt XML tree. must be freed by caller with xml_free + * @param[out] xt XML tree. Free with xml_free. + * Either or . * @retval 0 OK * @retval -1 Error, fatal or xml * @code * cxobj *xt = NULL; - * if (clicon_rpc_get_config(h, "running", "/", 0, &xt) < 0) + * if (clicon_rpc_get_config(h, "running", "/", &xt) < 0) * err; + * if ((xerr = xpath_first(xt, "/rpc-error")) != NULL){ + * clicon_rpc_generate_error(xerr); + * err; + * } * if (xt) * xml_free(xt); * @endcode + * @see clicon_rpc_generate_error */ int clicon_rpc_get_config(clicon_handle h, char *db, char *xpath, - int errmode, cxobj **xt) { int retval = -1; struct clicon_msg *msg = NULL; cbuf *cb = NULL; cxobj *xret = NULL; - cxobj *xerr; cxobj *xd; if ((cb = cbuf_new()) == NULL) @@ -267,22 +269,12 @@ clicon_rpc_get_config(clicon_handle h, goto done; if (clicon_rpc_msg(h, msg, &xret, NULL) < 0) goto done; - if (errmode == 0){ /* Move this to caller */ - if ((xerr = xpath_first(xret, "//rpc-error")) != NULL){ - clicon_rpc_generate_error(xerr); + /* Send xml error back: first check error, then ok */ + if ((xd = xpath_first(xret, "/rpc-reply/rpc-error")) != NULL) + xd = xml_parent(xd); /* point to rpc-reply */ + else if ((xd = xpath_first(xret, "/rpc-reply/data/config")) == NULL) + if ((xd = xml_new("config", NULL)) == NULL) goto done; - } - if ((xd = xpath_first(xret, "//data/config")) == NULL) - if ((xd = xml_new("config", NULL)) == NULL) - goto done; - } - else{ /* Send xml error back (this should be default behaviour) */ - if ((xd = xpath_first(xret, "//rpc-error")) == NULL){ - if ((xd = xpath_first(xret, "//data/config")) == NULL) - if ((xd = xml_new("config", NULL)) == NULL) - goto done; - } - } if (xt){ if (xml_rm(xd) < 0) goto done; diff --git a/lib/src/clixon_yang.c b/lib/src/clixon_yang.c index eeee4223..79717df5 100644 --- a/lib/src/clixon_yang.c +++ b/lib/src/clixon_yang.c @@ -71,10 +71,6 @@ #include "clixon_yang_type.h" #include "clixon_yang_parse.h" -/* Instead of using dynamic type lookup, use a cache that is evaluated early - for static scope type binding */ -#define YANG_TYPE_CACHE 1 - /* Mapping between yang keyword string <--> clicon constants */ static const map_str2int ykmap[] = { @@ -1392,7 +1388,7 @@ yang_parse_file(clicon_handle h, * @param[in] module Name of main YANG module. * @param[out] fbuf Buffer containing filename * - * @retval 1 Match founbd, Most recent entry returned in fbuf + * @retval 1 Match found, Most recent entry returned in fbuf * @retval 0 No matching entry found * @retval -1 Error */ @@ -1406,17 +1402,20 @@ yang_parse_find_match(clicon_handle h, struct dirent *dp = NULL; int ndp; cbuf *regex = NULL; - char *regexstr; if ((regex = cbuf_new()) == NULL){ clicon_err(OE_YANG, errno, "cbuf_new"); goto done; } - cprintf(regex, "^%s.*(.yang)$", module); - regexstr = cbuf_get(regex); + /* RFC 6020: The name of the file SHOULD be of the form: + module-or-submodule-name ['@' revision-date] ( '.yang' / '.yin' ) + revision-date ::= 4DIGIT "-" 2DIGIT "-" 2DIGIT + */ + cprintf(regex, "^%s(@[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9])?(.yang)$", + module); if ((ndp = clicon_file_dirent(yang_dir, &dp, - regexstr, + cbuf_get(regex), S_IFREG)) < 0) goto done; /* Entries are sorted, last entry should be most recent date */ @@ -1587,10 +1586,9 @@ yang_parse(clicon_handle h, /* Add top module name as dbspec-name */ clicon_dbspec_name_set(h, ymod->ys_argument); -#ifdef YANG_TYPE_CACHE /* Resolve all types */ yang_apply((yang_node*)ysp, ys_resolve_type, NULL); -#endif + /* Step 2: Macro expansion of all grouping/uses pairs. Expansion needs marking */ if (yang_expand((yang_node*)ysp) < 0) goto done; diff --git a/lib/src/clixon_yang_type.c b/lib/src/clixon_yang_type.c index 3647f039..d3028b72 100644 --- a/lib/src/clixon_yang_type.c +++ b/lib/src/clixon_yang_type.c @@ -178,7 +178,8 @@ yang_type_cache_get(yang_type_cache *ycache, } int -yang_type_cache_cp(yang_type_cache **ycnew, yang_type_cache *ycold) +yang_type_cache_cp(yang_type_cache **ycnew, + yang_type_cache *ycold) { int retval = -1; int options; @@ -211,7 +212,8 @@ yang_type_cache_free(yang_type_cache *ycache) /*! Resolve types: populate type caches */ int -ys_resolve_type(yang_stmt *ys, void *arg) +ys_resolve_type(yang_stmt *ys, + void *arg) { int retval = -1; int options = 0x0; @@ -333,7 +335,9 @@ cv2yang_type(enum cv_type cv_type) * @param[out] cvtype */ int -clicon_type2cv(char *origtype, char *restype, enum cv_type *cvtype) +clicon_type2cv(char *origtype, + char *restype, + enum cv_type *cvtype) { int retval = -1; @@ -700,7 +704,7 @@ ys_typedef_up(yang_stmt *ys) This is a sanity check of base identity of identity-ref and for identity statements. -Return true if node is identityref and is derived from identity_name + 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 @@ -718,7 +722,8 @@ Return true if node is identityref and is derived from identity_name Så vad är det denna function ska göra? Svar: 1 */ yang_stmt * -yang_find_identity(yang_stmt *ys, char *identity) +yang_find_identity(yang_stmt *ys, + char *identity) { char *id; char *prefix = NULL;