From 50522df3d9f685233df653fc19bb5cea9fbfaa6f Mon Sep 17 00:00:00 2001 From: Olof hagsand Date: Sun, 22 Apr 2018 21:36:55 +0200 Subject: [PATCH] Showing syntax using CLI commands was broekn and is fixed. --- CHANGELOG.md | 1 + lib/clixon/clixon_options.h | 3 +- lib/src/clixon_xml_map.c | 107 ++++++++++++----------------- test/test_cli.sh | 5 +- test/test_netconf.sh | 3 +- yang/clixon-config@2018-02-12.yang | 18 ++++- 6 files changed, 67 insertions(+), 70 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 01675118..e56752d8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -103,6 +103,7 @@ enables saved files to be used as datastore without any editing. Thanks Matt. * Added cli_show_version() ### Corrected Bugs +* Showing syntax using CLI commands was broekn and is fixed. * Fixed issue https://github.com/clicon/clixon/issues/18 RPC response issues reported by Stephen Jones at Netgate * Fixed issue https://github.com/clicon/clixon/issues/17 special character in strings can break RPCs reported by David Cornejo at Netgate. * This was a large rewright of XML parsing and output due to CharData not correctly encoded according to https://www.w3.org/TR/2008/REC-xml-20081126. diff --git a/lib/clixon/clixon_options.h b/lib/clixon/clixon_options.h index f6854d15..1f95c73a 100644 --- a/lib/clixon/clixon_options.h +++ b/lib/clixon/clixon_options.h @@ -50,7 +50,6 @@ /*! Controls how keywords a generated in CLI syntax / prints from object model * Example YANG: - * list a {a.b[] $!x $y: * list a { * key x; * leaf x; @@ -63,7 +62,7 @@ enum genmodel_type{ GT_ERR =-1, /* Error */ GT_NONE=0, /* No extra keywords */ - GT_VARS, /* Keywords on non-index variables */ + GT_VARS, /* Keywords on non-key variables */ GT_ALL, /* Keywords on all variables */ }; diff --git a/lib/src/clixon_xml_map.c b/lib/src/clixon_xml_map.c index 917131f7..8524a413 100644 --- a/lib/src/clixon_xml_map.c +++ b/lib/src/clixon_xml_map.c @@ -89,19 +89,6 @@ #include "clixon_xml_sort.h" #include "clixon_xml_map.h" -/* - * A node is a leaf if it contains a body. - */ -static cxobj * -leaf(cxobj *xn) -{ - cxobj *xc = NULL; - - while ((xc = xml_child_each(xn, xc, CX_BODY)) != NULL) - break; - return xc; -} - /*! x is element and has eactly one child which in turn has none */ static int tleaf(cxobj *x) @@ -118,6 +105,7 @@ tleaf(cxobj *x) /*! Translate XML -> TEXT * @param[in] level print 4 spaces per level in front of each line + * XXX rewrite using YANG and remove encrypted password KLUDGE */ int xml2txt(FILE *f, @@ -184,69 +172,60 @@ xml2cli(FILE *f, { int retval = -1; cxobj *xe = NULL; - char *term; - int bool; - int nr; - int i; - cbuf *cbpre; - // yang_stmt *ys; + cbuf *cbpre = NULL; + yang_stmt *ys; + int match; + char *body; - // ys = yang_spec(x); + ys = xml_spec(x); + if (ys->ys_keyword == Y_LEAF || ys->ys_keyword == Y_LEAF_LIST){ + if (prepend0) + fprintf(f, "%s", prepend0); + body = xml_body(x); + if (gt == GT_ALL || gt == GT_VARS) + fprintf(f, "%s ", xml_name(x)); + if (index(body, ' ')) + fprintf(f, "\"%s\"", body); + else + fprintf(f, "%s", body); + fprintf(f, "\n"); + goto ok; + } /* Create prepend variable string */ if ((cbpre = cbuf_new()) == NULL){ clicon_err(OE_PLUGIN, errno, "cbuf_new"); goto done; } - nr = xml_child_nr(x); - if (!nr){ - if (xml_type(x) == CX_BODY) - term = xml_value(x); - else - term = xml_name(x); - if (prepend0) - fprintf(f, "%s ", prepend0); - if (index(term, ' ')) - fprintf(f, "\"%s\"\n", term); - else - fprintf(f, "%s\n", term); - retval = 0; - goto done; - } if (prepend0) cprintf(cbpre, "%s", prepend0); - /* bool determines when to print a variable keyword: - !leaf T for all (ie parameter) - index GT_NONE F - index GT_VARS F - index GT_ALL T - !index GT_NONE F - !index GT_VARS T - !index GT_ALL T - */ - bool = !leaf(x) || gt == GT_ALL || (gt == GT_VARS); -// bool = (!x->xn_index || gt == GT_ALL); - if (bool){ - if (cbuf_len(cbpre)) - cprintf(cbpre, " "); - cprintf(cbpre, "%s", xml_name(x)); - } - xe = NULL; - /* First child is unique, then add that, before looping. */ - i = 0; - while ((xe = xml_child_each(x, xe, -1)) != NULL){ - /* Dont call this if it is index and there are other following */ - if (0 && i < nr-1) - ; - else - if (xml2cli(f, xe, cbuf_get(cbpre), gt) < 0) + cprintf(cbpre, "%s ", xml_name(x)); + + if (ys->ys_keyword == Y_LIST){ + /* If list then first loop through keys */ + xe = NULL; + while ((xe = xml_child_each(x, xe, -1)) != NULL){ + if ((match = yang_key_match((yang_node*)ys, xml_name(xe))) < 0) goto done; - if (0){ /* assume index is first, otherwise need one more while */ + if (!match) + continue; if (gt == GT_ALL) - cprintf(cbpre, " %s", xml_name(xe)); - cprintf(cbpre, " %s", xml_value(xml_child_i(xe, 0))); + cprintf(cbpre, "%s ", xml_name(xe)); + cprintf(cbpre, "%s ", xml_body(xe)); } - i++; } + /* Then loop through all other (non-keys) */ + xe = NULL; + while ((xe = xml_child_each(x, xe, -1)) != NULL){ + if (ys->ys_keyword == Y_LIST){ + if ((match = yang_key_match((yang_node*)ys, xml_name(xe))) < 0) + goto done; + if (match) + continue; + } + if (xml2cli(f, xe, cbuf_get(cbpre), gt) < 0) + goto done; + } + ok: retval = 0; done: if (cbpre) diff --git a/test/test_cli.sh b/test/test_cli.sh index 51a2ea5e..ec71a707 100755 --- a/test/test_cli.sh +++ b/test/test_cli.sh @@ -58,7 +58,7 @@ new "cli configure" expectfn "$clixon_cli -1 -f $cfg set interfaces interface eth/0/0" "^$" new "cli show configuration" -expectfn "$clixon_cli -1 -f $cfg show conf cli" "^interfaces interface name eth/0/0" "interfaces interface enabled true$" +expectfn "$clixon_cli -1 -f $cfg show conf cli" "^interfaces interface eth/0/0 enabled true" new "cli configure using encoded chars data <&" expectfn "$clixon_cli -1 -f $cfg set interfaces interface eth/0/0 description \"foo<&bar\"" "" @@ -101,7 +101,8 @@ new "cli load" expectfn "$clixon_cli -1 -f $cfg -l o load /tmp/foo" "^$" new "cli check load" -expectfn "$clixon_cli -1 -f $cfg -l o show conf cli" "^interfaces interface name eth/0/0" "interfaces interface enabled true$" +expectfn "$clixon_cli -1 -f $cfg -l o show conf cli" "^interfaces interface name eth/0/0 type bgp +interfaces interface eth/0/0 ipv4 enabled true" new "cli debug" expectfn "$clixon_cli -1 -f $cfg -l o debug level 1" "^$" diff --git a/test/test_netconf.sh b/test/test_netconf.sh index 7b66e88e..b6fc58ac 100755 --- a/test/test_netconf.sh +++ b/test/test_netconf.sh @@ -144,7 +144,8 @@ new "netconf get replaced config" expecteof "$clixon_netconf -qf $cfg -y $fyang" "]]>]]>" "^eth& t< > trueeth1ethtrueeth2ethtrue]]>]]>$" new "cli show configuration eth& - encoding tests" -expectfn "$clixon_cli -1 -f $cfg -y $fyang show conf cli" "interfaces interface name eth&" +expectfn "$clixon_cli -1 -f $cfg -y $fyang show conf cli" "interfaces interface eth& type t<> +interfaces interface eth& enabled true" new "netconf discard-changes" expecteof "$clixon_netconf -qf $cfg -y $fyang" "]]>]]>" "^]]>]]>$" diff --git a/yang/clixon-config@2018-02-12.yang b/yang/clixon-config@2018-02-12.yang index 58ff73f8..84dc8622 100644 --- a/yang/clixon-config@2018-02-12.yang +++ b/yang/clixon-config@2018-02-12.yang @@ -82,6 +82,22 @@ module clixon-config { } } } + typedef cli_genmodel_type{ + description + "How to generate CLI from YANG model, + eg list a{ key x; leaf x; leaf y;}"; + type enumeration{ + enum NONE{ + description "No extra keywords: a "; + } + enum VARS{ + description "Keywords on non-key variables: a y "; + } + enum ALL{ + description "Keywords on all variables: a x y "; + } + } + } typedef nacm_mode{ description "Mode of RFC8341 Network Configuration Access Control Model. @@ -204,7 +220,7 @@ module clixon-config { description "Generate code for CLI completion of existing db symbols"; } leaf CLICON_CLI_GENMODEL_TYPE { - type string; + type cli_genmodel_type; default "VARS"; description "How to generate and show CLI syntax: VARS|ALL"; }