From bd5b51d8608ecc8d7521ab7140d501e8765e407f Mon Sep 17 00:00:00 2001 From: Olof hagsand Date: Wed, 3 May 2023 13:57:13 +0200 Subject: [PATCH] CLI edit modes and mountpoints --- CHANGELOG.md | 8 ++++ apps/cli/cli_auto.c | 65 ++++++++++++------------- apps/cli/cli_common.c | 28 +++++++++++ apps/cli/cli_common.h | 7 +-- apps/cli/cli_show.c | 98 ++++++++++++++++++++++++++------------ lib/src/clixon_xml_nsctx.c | 1 + 6 files changed, 138 insertions(+), 69 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fd0870d7..833afc5a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ # Clixon Changelog +* [6.3.0](#630) Expected: July 2023 * [6.2.0](#620) 30 April 2023 * [6.1.0](#610) 19 Feb 2023 * [6.0.0](#600) 29 Nov 2022 @@ -39,6 +40,13 @@ * [3.3.2](#332) Aug 27 2017 * [3.3.1](#331) June 7 2017 +## 6.3.0 +Expected: July 2023 + +### Corrected Bugs + +* Fixed autocli edit modes for schema mounts + ## 6.2.0 30 April 2023 diff --git a/apps/cli/cli_auto.c b/apps/cli/cli_auto.c index 71ad99ab..cbf9189f 100644 --- a/apps/cli/cli_auto.c +++ b/apps/cli/cli_auto.c @@ -97,40 +97,16 @@ co2apipath(cg_obj *co) return cv_string_get(cv); } -/* Append to cvv1 to cvv0 - * @note if cvv0 is non-null, the first element of cvv1 is skipped - */ -static cvec* -cvec_append(cvec *cvv0, - cvec *cvv1) -{ - cvec *cvv2 = NULL; - cg_var *cv; - - if (cvv0 == NULL){ - if ((cvv2 = cvec_dup(cvv1)) == NULL){ - clicon_err(OE_UNIX, errno, "cvec_dup"); - return NULL; - } - } - else{ - if ((cvv2 = cvec_dup(cvv0)) == NULL){ - clicon_err(OE_UNIX, errno, "cvec_dup"); - return NULL; - } - cv = NULL; /* Append cvv1 to cvv2 */ - while ((cv = cvec_each1(cvv1, cv)) != NULL) - cvec_append_var(cvv2, cv); - } - return cvv2; -} - /*! Enter a CLI edit mode + * * @param[in] h CLICON handle * @param[in] cvv Vector of variables from CLIgen command-line * @param[in] argv Vector of user-supplied keywords + * @retval 0 OK + * @retval -1 Error * Format of argv: * Generated API PATH (This is where we are in the tree) + * [] Extra api-path from mount-point * Name of generated cligen parse-tree, eg "datamodel" * Note api_path_fmt is not used in code but must be there in order to pick coorig from matching * code @@ -143,19 +119,28 @@ cli_auto_edit(clicon_handle h, int retval = -1; char *api_path_fmt; /* xml key format */ char *api_path = NULL; - cg_var *cv; char *treename; pt_head *ph; cg_obj *co; cg_obj *coorig; cvec *cvv2 = NULL; /* cvv2 = cvv0 + cvv1 */ + int argc = 0; + char *str; + char *mtpoint = NULL; - if (cvec_len(argv) != 2){ - clicon_err(OE_PLUGIN, EINVAL, "Usage: %s(api_path_fmt>, )", __FUNCTION__); + if (cvec_len(argv) != 2 && cvec_len(argv) != 3){ + clicon_err(OE_PLUGIN, EINVAL, "Usage: %s(api_path_fmt>*, )", __FUNCTION__); goto done; } - cv = cvec_i(argv, 1); - treename = cv_string_get(cv); + api_path_fmt = cv_string_get(cvec_i(argv, argc++)); + str = cv_string_get(cvec_i(argv, argc++)); + if (str && str[0] == '/'){ /* ad-hoc to see if 2nd arg is mountpoint */ + mtpoint = str; + clicon_debug(1, "%s mtpoint:%s", __FUNCTION__, mtpoint); + treename = cv_string_get(cvec_i(argv, argc++)); + } + else + treename = str; /* Find current cligen tree */ if ((ph = cligen_ph_find(cli_cligen(h), treename)) == NULL){ clicon_err(OE_PLUGIN, 0, "No such parsetree header: %s", treename); @@ -191,6 +176,15 @@ cli_auto_edit(clicon_handle h, /* Store this as edit-mode */ if (clicon_data_set(h, "cli-edit-mode", api_path) < 0) goto done; + if (mtpoint){ + char *mtpoint2; + if ((mtpoint2 = strdup(mtpoint)) == NULL){ + clicon_err(OE_UNIX, errno, "strdup"); + goto done; + } + if (clicon_data_set(h, "cli-edit-mtpoint", mtpoint2) < 0) + goto done; + } if (clicon_data_cvec_set(h, "cli-edit-cvv", cvv2) < 0) goto done; if (co->co_filter){ @@ -437,12 +431,13 @@ struct findpt_arg{ }; /*! Iterate through parse-tree to find first argument set by cli_generate code + * * @see cg_applyfn_t * @param[in] co CLIgen parse-tree object * @param[in] arg Argument, cast to application-specific info - * @retval -1 Error: break and return - * @retval 0 OK and continue * @retval 1 OK and return (abort iteration) + * @retval 0 OK and continue + * @retval -1 Error: break and return */ static int cli_auto_findpt(cg_obj *co, diff --git a/apps/cli/cli_common.c b/apps/cli/cli_common.c index ff555f2e..1780f3e0 100644 --- a/apps/cli/cli_common.c +++ b/apps/cli/cli_common.c @@ -1593,3 +1593,31 @@ cli_restart_plugin(clicon_handle h, return retval; } +/* Append cvv1 to cvv0 and return a new cvec + * + * @note if cvv0 is non-null, the first element of cvv1 is skipped + */ +cvec* +cvec_append(cvec *cvv0, + cvec *cvv1) +{ + cvec *cvv2 = NULL; + cg_var *cv; + + if (cvv0 == NULL){ + if ((cvv2 = cvec_dup(cvv1)) == NULL){ + clicon_err(OE_UNIX, errno, "cvec_dup"); + return NULL; + } + } + else{ + if ((cvv2 = cvec_dup(cvv0)) == NULL){ + clicon_err(OE_UNIX, errno, "cvec_dup"); + return NULL; + } + cv = NULL; /* Append cvv1 to cvv2 */ + while ((cv = cvec_each1(cvv1, cv)) != NULL) + cvec_append_var(cvv2, cv); + } + return cvv2; +} diff --git a/apps/cli/cli_common.h b/apps/cli/cli_common.h index 79217c40..05e05080 100644 --- a/apps/cli/cli_common.h +++ b/apps/cli/cli_common.h @@ -39,9 +39,10 @@ #ifndef _CLI_COMMON_H_ #define _CLI_COMMON_H_ -void cli_signal_block(clicon_handle h); -void cli_signal_unblock(clicon_handle h); -int mtpoint_paths(yang_stmt *yspec0, char *mtpoint, char *api_path_fmt1, char **api_path_fmt01); +void cli_signal_block(clicon_handle h); +void cli_signal_unblock(clicon_handle h); +int mtpoint_paths(yang_stmt *yspec0, char *mtpoint, char *api_path_fmt1, char **api_path_fmt01); +cvec *cvec_append(cvec *cvv0, cvec *cvv1); /* If you do not find a function here it may be in clixon_cli_api.h which is the external API */ diff --git a/apps/cli/cli_show.c b/apps/cli/cli_show.c index 83f8280b..16f4e1dd 100644 --- a/apps/cli/cli_show.c +++ b/apps/cli/cli_show.c @@ -52,6 +52,7 @@ #include #include #include +#include #include #include #include @@ -60,7 +61,6 @@ #include #include #include -#include /* cligen */ #include @@ -216,6 +216,9 @@ expand_dbvar(void *h, yang_stmt *ytype; char *mtpoint = NULL; yang_stmt *yspec0 = NULL; + yang_stmt *yspec; + yang_stmt *yu = NULL; + cvec *nsc0 = NULL; if (argv == NULL || (cvec_len(argv) != 2 && cvec_len(argv) != 3)){ clicon_err(OE_PLUGIN, EINVAL, "requires arguments: []"); @@ -245,24 +248,12 @@ expand_dbvar(void *h, cv = cvec_i(argv, 2); mtpoint = cv_string_get(cv); } - if (mtpoint){ - /* Get combined api-path01 */ - if (mtpoint_paths(yspec0, mtpoint, api_path_fmt, &api_path_fmt01) < 0) - goto done; - /* Transform template format string + cvv to actual api-path - * cvv_i indicates if all cvv entries were used - */ - if (api_path_fmt2api_path(api_path_fmt01, cvv, &api_path, &cvvi) < 0) - goto done; - } - else { - /* api_path_fmt = /interface/%s/address/%s - * api_path: --> /interface/eth0/address/.* - * xpath: --> /interface/[name="eth0"]/address - */ - if (api_path_fmt2api_path(api_path_fmt, cvv, &api_path, &cvvi) < 0) - goto done; - } + /* api_path_fmt = /interface/%s/address/%s + * api_path: --> /interface/eth0/address/.* + * xpath: --> /interface/[name="eth0"]/address + */ + if (api_path_fmt2api_path(api_path_fmt, cvv, &api_path, &cvvi) < 0) + goto done; /* Create config top-of-tree */ if ((xtop = xml_new(DATASTORE_TOP_SYMBOL, NULL, CX_ELMNT)) == NULL) goto done; @@ -271,8 +262,15 @@ expand_dbvar(void *h, * xpath2xml would have worked!! * XXX: but y is just the first in this list, there could be other y:s? */ + yspec = yspec0; /* may be reset to mount yspec below */ if (api_path){ - if ((ret = api_path2xml(api_path, yspec0, xtop, YC_DATANODE, 0, &xbot, &y, &xerr)) < 0) + if (mtpoint){ + if (yang_path_arg(yspec0, mtpoint, &yu) < 0) + goto done; + if (yang_mount_get(yu, mtpoint, &yspec) < 0) + goto done; + } + if ((ret = api_path2xml(api_path, yspec, xtop, YC_DATANODE, 0, &xbot, &y, &xerr)) < 0) goto done; if (ret == 0){ // XXX cf cli_dbxml @@ -283,13 +281,20 @@ expand_dbvar(void *h, if (y==NULL) goto ok; /* Transform api-path to xpath for netconf */ - if (api_path2xpath(api_path, yspec0, &xpath, &nsc, NULL) < 0) + if (api_path2xpath(api_path, yspec, &xpath, &nsc, NULL) < 0) goto done; - if ((cbxpath = cbuf_new()) == NULL){ clicon_err(OE_UNIX, errno, "cbuf_new"); goto done; } + if (mtpoint){ + cprintf(cbxpath, "%s", mtpoint); + if (xml_nsctx_yangspec(yspec0, &nsc0) < 0) + goto done; + cv = NULL; /* Append cvv1 to cvv2 */ + while ((cv = cvec_each(nsc0, cv)) != NULL) + cvec_append_var(nsc, cv); + } cprintf(cbxpath, "%s", xpath); if (clicon_option_bool(h, "CLICON_CLI_EXPAND_LEAFREF") && (ytype = yang_find(y, Y_TYPE, NULL)) != NULL && @@ -376,6 +381,8 @@ expand_dbvar(void *h, ok: retval = 0; done: + if (nsc0) + cvec_free(nsc0); if (api_path_fmt01) free(api_path_fmt01); if (cbxpath) @@ -558,7 +565,7 @@ done: * @param[in] argc Index into argv * @param[out] format Output format * @retval 0 OK - * @retval -1 Error + * @retval -1 Error */ static int cli_show_option_format(cvec *argv, @@ -584,7 +591,7 @@ cli_show_option_format(cvec *argv, * @param[in] argc Index into argv * @param[out] bool result boolean: 0 or 1 * @retval 0 OK - * @retval -1 Error + * @retval -1 Error */ static int cli_show_option_bool(cvec *argv, @@ -624,7 +631,7 @@ cli_show_option_bool(cvec *argv, * @param[in] withdefault RFC 6243 with-default modes * @param[in] extdefault with-defaults with propriatary extensions * @retval 0 OK - * @retval -1 Error + * @retval -1 Error */ static int cli_show_option_withdefault(cvec *argv, @@ -988,8 +995,6 @@ cli_show_auto(clicon_handle h, * @endcode * @see cli_show_auto autocli with expansion * @see cli_show_config with no autocli coupling - * - * XXX merge cli_show_auto and cli_show_auto_mode */ int cli_show_auto_mode(clicon_handle h, @@ -1008,13 +1013,23 @@ cli_show_auto_mode(clicon_handle h, int argc = 0; int skiptop = 0; char *xpath = NULL; + yang_stmt *yspec0; yang_stmt *yspec; char *api_path = NULL; + char *mtpoint = NULL; + yang_stmt *yu; + cbuf *cbxpath = NULL; + cvec *nsc0 = NULL; + cg_var *cv; if (cvec_len(argv) < 2 || cvec_len(argv) > 7){ clicon_err(OE_PLUGIN, EINVAL, "Received %d arguments. Expected: [ ]", cvec_len(argv)); goto done; } + if ((yspec0 = clicon_dbspec_yang(h)) == NULL){ + clicon_err(OE_FATAL, 0, "No DB_SPEC"); + goto done; + } dbname = cv_string_get(cvec_i(argv, argc++)); if (cvec_len(argv) > argc) if (cli_show_option_format(argv, argc++, &format) < 0) @@ -1041,23 +1056,44 @@ cli_show_auto_mode(clicon_handle h, ; else api_path = "/"; - if ((yspec = clicon_dbspec_yang(h)) == NULL){ - clicon_err(OE_FATAL, 0, "No DB_SPEC"); - goto done; + if (clicon_data_get(h, "cli-edit-mtpoint", &mtpoint) == 0 && strlen(mtpoint)){ + if (yang_path_arg(yspec0, mtpoint, &yu) < 0) + goto done; + if (yang_mount_get(yu, mtpoint, &yspec) < 0) + goto done; } + else + yspec = yspec0; if (api_path2xpath(api_path, yspec, &xpath, &nsc, NULL) < 0) goto done; if (xpath == NULL){ clicon_err(OE_FATAL, 0, "Invalid api-path: %s", api_path); goto done; } + if ((cbxpath = cbuf_new()) == NULL){ + clicon_err(OE_UNIX, errno, "cbuf_new"); + goto done; + } + if (mtpoint){ + cprintf(cbxpath, "%s", mtpoint); + if (xml_nsctx_yangspec(yspec0, &nsc0) < 0) + goto done; + cv = NULL; /* Append cvv1 to cvv2 */ + while ((cv = cvec_each(nsc0, cv)) != NULL) + cvec_append_var(nsc, cv); + } + cprintf(cbxpath, "%s", xpath); skiptop = (strcmp(xpath,"/") != 0); if (cli_show_common(h, dbname, format, pretty, state, withdefault, extdefault, - prepend, xpath, nsc, skiptop) < 0) + prepend, cbuf_get(cbxpath), nsc, skiptop) < 0) goto done; retval = 0; done: + if (nsc0) + cvec_free(nsc0); + if (cbxpath) + cbuf_free(cbxpath); if (nsc) xml_nsctx_free(nsc); if (xpath) diff --git a/lib/src/clixon_xml_nsctx.c b/lib/src/clixon_xml_nsctx.c index 087f2ce2..08b9a90a 100644 --- a/lib/src/clixon_xml_nsctx.c +++ b/lib/src/clixon_xml_nsctx.c @@ -319,6 +319,7 @@ xml_nsctx_node(cxobj *xn, * xml_nsctx_free(nsc) * @endcode * @see RFC7950 Sections 6.4.1 (and 9.9.2?) + * @see xml_nsctx_yangspec * @note Assume yn is in a yang structure (eg has parents and belongs to a (sub)module) */ int