diff --git a/CHANGELOG b/CHANGELOG index 4c2b8dd1..3731f1f6 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -29,7 +29,13 @@ # # ***** END LICENSE BLOCK ***** -- show_configuration and cli_copy_object added as generic cli commands +- cli_copy_config added as generic cli command +- cli_show_config added as generic cli command + Replace all show_confv*() and show_conf*() with cli_show_config() + Example: replace: + show_confv_as_json("candidate","/sender"); + with: + cli_show_config("candidate","json","/sender"); - Alternative yang spec option -y added to all applications - Many clicon special string functions have been removed - The netconf support has been extended with lock/unlock @@ -69,18 +75,40 @@ - Netconf startup configuration support. Set CLICON_USE_STARTUP_CONFIG to 1 to enable. Eg, if backend_main is started with -CIr startup will be copied to running. + - Added ".." as valid step in xpath + - Use restconf format for internal xmldb keys. Eg /a/b=3,4 -- List keys with special characters are RFC 3986 encoded. -- Changed example to use multiple cli callbacks -- Added cli multiple callback and expand support. Use options - CLICON_CLIGEN_CALLBACK_SINGLE_ARG and CLICON_CLIGEN_EXPAND_SINGLE_ARG - to control these. - The multiple support for expand callbacks is enabled but not for callbacks - since this causes problems for legacy applications. - If you change to multiple argument callbacks change all cli callback functions. - Library functions in clixon_cli_api.h (e.g cli_commit) is rewritten in new - for (eg cli_commitv). See clixon_cli_api.h for new names. + +- List keys with special characters RFC 3986 encoded. + +- Replaced cli expand functions with single to multiple args + This change is _not_ backward compatible + This effects all calls to expand_dbvar() or user-defined + expand callbacks + +- Replaced cli callback functions with single arg to multiple args + This change is _not_ backward compatible. + You are affected if you + (1) use system callbacks (i.e. in clixon_cli_api.h) + (2) write your own cli callbacks + + If you use cli callbacks, you need to rewrite cli callbacks from eg: + load("Comment") ,load_config_file("filename replace"); + to: + load("Comment") ,load_config_file("filename", "replace"); + + If you write your own, you need to change the callback signature from; + int cli_callback(clicon_handle h, cvec *vars, cg_var *arg) + to: + int cli_callback(clicon_handle h, cvec *vars, cvec *argv) + and rewrite the code to handle argv instead of arg. + These are the system functions affected: + cli_set, cli_merge, cli_del, cli_debug_backend, cli_set_mode, + cli_start_shell, cli_quit, cli_commit, cli_validate, compare_dbs, + load_config_file, save_config_file, delete_all, discard_changes, cli_notify, + show_yang, show_conf_xpath + - Added --with-cligen and --with-qdbm configure options - Added union type check for non-cli (eg xml) input - Empty yang type. Relaxed yang types for unions, eg two strings with different length. diff --git a/apps/cli/cli_common.c b/apps/cli/cli_common.c index 49496c97..92882d5b 100644 --- a/apps/cli/cli_common.c +++ b/apps/cli/cli_common.c @@ -197,10 +197,10 @@ cli_signal_flush(clicon_handle h) * @see cli_callback_generate where arg is generated */ static int -cli_dbxmlv(clicon_handle h, - cvec *cvv, - cvec *argv, - enum operation_type op) +cli_dbxml(clicon_handle h, + cvec *cvv, + cvec *argv, + enum operation_type op) { int retval = -1; char *str = NULL; @@ -253,40 +253,54 @@ cli_dbxmlv(clicon_handle h, } int -cli_setv(clicon_handle h, cvec *cvv, cvec *argv) +cli_set(clicon_handle h, cvec *cvv, cvec *argv) { int retval = 1; - if (cli_dbxmlv(h, cvv, argv, OP_REPLACE) < 0) + if (cli_dbxml(h, cvv, argv, OP_REPLACE) < 0) goto done; retval = 0; done: return retval; } +int cli_setv(clicon_handle h, cvec *vars, cvec *argv) +{ + return cli_set(h, vars, argv); +} int -cli_mergev(clicon_handle h, cvec *cvv, cvec *argv) +cli_merge(clicon_handle h, cvec *cvv, cvec *argv) { int retval = -1; - if (cli_dbxmlv(h, cvv, argv, OP_MERGE) < 0) + if (cli_dbxml(h, cvv, argv, OP_MERGE) < 0) goto done; retval = 0; done: return retval; } +int cli_mergev(clicon_handle h, cvec *vars, cvec *argv) +{ + return cli_merge(h, vars, argv); +} + int -cli_delv(clicon_handle h, cvec *cvv, cvec *argv) +cli_del(clicon_handle h, cvec *cvv, cvec *argv) { int retval = -1; - if (cli_dbxmlv(h, cvv, argv, OP_REMOVE) < 0) + if (cli_dbxml(h, cvv, argv, OP_REMOVE) < 0) goto done; retval = 0; done: return retval; } +int cli_delv(clicon_handle h, cvec *vars, cvec *argv) +{ + return cli_del(h, vars, argv); +} + /*! Set debug level on CLI client (not backend daemon) * @param[in] h Clicon handle @@ -296,7 +310,7 @@ cli_delv(clicon_handle h, cvec *cvv, cvec *argv) * _or_ if a 'level' variable is present in vars use that value instead. */ int -cli_debug_cliv(clicon_handle h, +cli_debug_cli(clicon_handle h, cvec *vars, cvec *argv) { @@ -318,6 +332,10 @@ cli_debug_cliv(clicon_handle h, done: return retval; } +int cli_debug_cliv(clicon_handle h, cvec *vars, cvec *argv) +{ + return cli_debug_cli(h, vars, argv); +} /*! Set debug level on backend daemon (not CLI) * @param[in] h Clicon handle @@ -327,9 +345,9 @@ cli_debug_cliv(clicon_handle h, * _or_ if a 'level' variable is present in vars use that value instead. */ int -cli_debug_backendv(clicon_handle h, - cvec *vars, - cvec *argv) +cli_debug_backend(clicon_handle h, + cvec *vars, + cvec *argv) { int retval = -1; cg_var *cv; @@ -348,11 +366,15 @@ cli_debug_backendv(clicon_handle h, done: return retval; } +int cli_debug_backendv(clicon_handle h, cvec *vars, cvec *argv) +{ + return cli_debug_backend(h, vars, argv); +} /*! Set syntax mode */ int -cli_set_modev(clicon_handle h, +cli_set_mode(clicon_handle h, cvec *vars, cvec *argv) { @@ -369,14 +391,18 @@ cli_set_modev(clicon_handle h, done: return retval; } +int cli_set_modev(clicon_handle h, cvec *vars, cvec *argv) +{ + return cli_set_mode(h, vars, argv); +} /*! Start bash from cli callback * XXX Application specific?? */ int -cli_start_shellv(clicon_handle h, - cvec *vars, - cvec *argv) +cli_start_shell(clicon_handle h, + cvec *vars, + cvec *argv) { char *cmd; struct passwd *pw; @@ -426,23 +452,31 @@ cli_start_shellv(clicon_handle h, return 0; } +int cli_start_shellv(clicon_handle h, cvec *vars, cvec *argv) +{ + return cli_start_shell(h, vars, argv); +} /*! Generic quit callback */ int -cli_quitv(clicon_handle h, +cli_quit(clicon_handle h, cvec *vars, cvec *argv) { cli_set_exiting(h, 1); return 0; } +int cli_quitv(clicon_handle h, cvec *vars, cvec *argv) +{ + return cli_quit(h, vars, argv); +} /*! Generic commit callback * @param[in] argv No arguments expected */ int -cli_commitv(clicon_handle h, +cli_commit(clicon_handle h, cvec *vars, cvec *argv) { @@ -456,11 +490,15 @@ cli_commitv(clicon_handle h, done: return retval; } +int cli_commitv(clicon_handle h, cvec *vars, cvec *argv) +{ + return cli_commit(h, vars, argv); +} /*! Generic validate callback */ int -cli_validatev(clicon_handle h, +cli_validate(clicon_handle h, cvec *vars, cvec *argv) { @@ -472,7 +510,10 @@ cli_validatev(clicon_handle h, done: return retval; } - +int cli_validatev(clicon_handle h, cvec *vars, cvec *argv) +{ + return cli_validate(h, vars, argv); +} /*! Compare two dbs using XML. Write to file and run diff */ @@ -541,7 +582,7 @@ compare_xmls(cxobj *xc1, * @param[in] arg arg: 0 as xml, 1: as text */ int -compare_dbsv(clicon_handle h, +compare_dbs(clicon_handle h, cvec *cvv, cvec *argv) { @@ -573,6 +614,10 @@ compare_dbsv(clicon_handle h, return retval; } +int compare_dbsv(clicon_handle h, cvec *vars, cvec *argv) +{ + return compare_dbs(h, vars, argv); +} /*! Load a configuration file to candidate database * Utility function used by cligen spec file @@ -589,9 +634,9 @@ compare_dbsv(clicon_handle h, * @see save_config_file */ int -load_config_filev(clicon_handle h, - cvec *cvv, - cvec *argv) +load_config_file(clicon_handle h, + cvec *cvv, + cvec *argv) { int ret = -1; struct stat st; @@ -669,6 +714,10 @@ load_config_filev(clicon_handle h, close(fd); return ret; } +int load_config_filev(clicon_handle h, cvec *vars, cvec *argv) +{ + return load_config_file(h, vars, argv); +} /*! Copy database to local file * Utility function used by cligen spec file @@ -686,9 +735,9 @@ load_config_filev(clicon_handle h, * @see load_config_file */ int -save_config_filev(clicon_handle h, - cvec *cvv, - cvec *argv) +save_config_file(clicon_handle h, + cvec *cvv, + cvec *argv) { int retval = -1; char *filename = NULL; @@ -736,14 +785,18 @@ save_config_filev(clicon_handle h, fclose(f); return retval; } +int save_config_filev(clicon_handle h, cvec *vars, cvec *argv) +{ + return save_config_file(h, vars, argv); +} /*! Delete all elements in a database * Utility function used by cligen spec file */ int -delete_allv(clicon_handle h, - cvec *cvv, - cvec *argv) +delete_all(clicon_handle h, + cvec *cvv, + cvec *argv) { char *dbstr; int retval = -1; @@ -765,16 +818,24 @@ delete_allv(clicon_handle h, done: return retval; } +int delete_allv(clicon_handle h, cvec *vars, cvec *argv) +{ + return delete_all(h, vars, argv); +} /*! Discard all changes in candidate and replace with running */ int -discard_changesv(clicon_handle h, - cvec *cvv, - cvec *argv) +discard_changes(clicon_handle h, + cvec *cvv, + cvec *argv) { return clicon_rpc_discard_changes(h); } +int discard_changesv(clicon_handle h, cvec *vars, cvec *argv) +{ + return discard_changes(h, vars, argv); +} /*! Copy from one database to another, eg running->startup * @param[in] argv a string: " " Copy from db1 to db2 @@ -864,9 +925,9 @@ cli_notification_cb(int s, * XXX: format is a memory leak */ int -cli_notifyv(clicon_handle h, - cvec *cvv, - cvec *argv) +cli_notify(clicon_handle h, + cvec *cvv, + cvec *argv) { char *stream = NULL; int retval = -1; @@ -897,6 +958,10 @@ cli_notifyv(clicon_handle h, done: return retval; } +int cli_notifyv(clicon_handle h, cvec *vars, cvec *argv) +{ + return cli_notify(h, vars, argv); +} /*! Lock database * @@ -976,13 +1041,13 @@ cli_unlock(clicon_handle h, * tovar: Name of variable containing name of object to copy to. * @code * cli spec: - * copy snd to , copy_object("candidate", "/sender[%s=%s]", "from", "n1", "n2"); + * copy snd to , cli_copy_config("candidate", "/sender[%s=%s]", "from", "n1", "n2"); * cli command: * copy snd from to to * @endcode */ int -cli_copy_object(clicon_handle h, +cli_copy_config(clicon_handle h, cvec *cvv, cvec *argv) { @@ -1080,176 +1145,6 @@ cli_copy_object(clicon_handle h, return retval; } -/* Here are backward compatible cligen callback functions used when - * the option: CLICON_CLIGEN_CALLBACK_SINGLE_ARG is set. - */ - -cb_single_arg(cli_set) -cb_single_arg(cli_merge) -cb_single_arg(cli_del) -cb_single_arg(cli_debug_cli) -cb_single_arg(cli_debug_backend) -cb_single_arg(cli_set_mode) -cb_single_arg(cli_start_shell) -cb_single_arg(cli_quit) -//cb_single_arg(cli_commit) -int cli_commit(clicon_handle h, cvec *cvv, cg_var *arg) -{ - int retval=-1; - cvec *argv = NULL; - - if (arg){ - if (cv_type_get(arg) > CGV_EMPTY){ - cligen_output(stderr, "%s: Illegal cvtype. This is most probably a single-argument cligen callback being used in a multi-argument setting. This can happen if option CLICON_CLIGEN_CALLBACK_SINGLE_ARG is 0 but you call a single argument callback (eg %s) from a .cli file. Please change to a multi-argument callback\n", __FUNCTION__, __FUNCTION__); - goto done; - } - if ((argv = cvec_from_var(arg)) == NULL){ - clicon_err(OE_UNIX, errno, "cvec_from_var"); - goto done; - } - } - retval = cli_commitv(h, cvv, argv); - done: - if (argv) cvec_free(argv); - return retval; -} - -cb_single_arg(cli_validate) -cb_single_arg(compare_dbs) -cb_single_arg(delete_all) -cb_single_arg(discard_changes) - -/* Follows some functions not covered by translation macro */ -int -load_config_file(clicon_handle h, - cvec *cvv, - cg_var *arg) -{ - int retval=-1; - cvec *argv; - cg_var *cv; - char *str; - char **vec = NULL; - int nvec; - - /* Split string into two parts and build a cvec of it and supply that to - the multi-arg callback */ - if (arg == NULL || (str = cv_string_get(arg)) == NULL){ - clicon_err(OE_PLUGIN, 0, "%s: requires string argument", __FUNCTION__); - goto done; - } - if ((vec = clicon_strsep(str, " ", &nvec)) == NULL) - goto done; - if (nvec != 2){ - clicon_err(OE_PLUGIN, 0, "Arg syntax is "); - goto done; - } - if ((argv = cvec_new(nvec)) == NULL){ - clicon_err(OE_UNIX, errno, "cvec_from_var"); - goto done; - } - cv = cvec_i(argv, 0); - cv_type_set(cv, CGV_STRING); - cv_string_set(cv, vec[0]); - cv = cvec_i(argv, 1); - cv_type_set(cv, CGV_STRING); - cv_string_set(cv, vec[1]); - - retval = load_config_filev(h, cvv, argv); - done: - if (vec) - free(vec); - return retval; -} - -int -save_config_file(clicon_handle h, - cvec *cvv, - cg_var *arg) -{ - int retval=-1; - cvec *argv; - cg_var *cv; - char *str; - char **vec = NULL; - int nvec; - - /* Split string into two parts and build a cvec of it and supply that to - the multi-arg callback */ - if (arg == NULL || (str = cv_string_get(arg)) == NULL){ - clicon_err(OE_PLUGIN, 0, "%s: requires string argument", __FUNCTION__); - goto done; - } - if ((vec = clicon_strsep(str, " ", &nvec)) == NULL) - goto done; - if (nvec != 2){ - clicon_err(OE_PLUGIN, 0, "Arg syntax is "); - goto done; - } - if ((argv = cvec_new(nvec)) == NULL){ - clicon_err(OE_UNIX, errno, "cvec_from_var"); - goto done; - } - cv = cvec_i(argv, 0); - cv_type_set(cv, CGV_STRING); - cv_string_set(cv, vec[0]); - cv = cvec_i(argv, 1); - cv_type_set(cv, CGV_STRING); - cv_string_set(cv, vec[1]); - - retval = save_config_filev(h, cvv, argv); - done: - if (vec) - free(vec); - return retval; -} - -int -cli_notify(clicon_handle h, - cvec *cvv, - cg_var *arg) -{ - int retval=-1; - cvec *argv; - cg_var *cv; - char *str; - char **vec = NULL; - int nvec; - - /* Split string into two parts and build a cvec of it and supply that to - the multi-arg callback */ - if (arg == NULL || (str = cv_string_get(arg)) == NULL){ - clicon_err(OE_PLUGIN, 0, "%s: requires string argument", __FUNCTION__); - goto done; - } - if ((vec = clicon_strsep(str, " ", &nvec)) == NULL) - goto done; - if (nvec != 2 && nvec != 3){ - clicon_err(OE_PLUGIN, 0, "Arg syntax is []"); - goto done; - } - if ((argv = cvec_new(nvec)) == NULL){ - clicon_err(OE_UNIX, errno, "cvec_from_var"); - goto done; - } - cv = cvec_i(argv, 0); - cv_type_set(cv, CGV_STRING); - cv_string_set(cv, vec[0]); - - cv = cvec_i(argv, 1); - cv_type_set(cv, CGV_STRING); - cv_string_set(cv, vec[1]); - if (nvec > 2){ - cv = cvec_i(argv, 2); - cv_type_set(cv, CGV_STRING); - cv_string_set(cv, vec[2]); - } - retval = cli_notifyv(h, cvv, argv); - done: - if (vec) - free(vec); - return retval; -} /*! set debug level on stderr (not syslog). * The level is either what is specified in arg as int argument. diff --git a/apps/cli/cli_generate.c b/apps/cli/cli_generate.c index bf7d9630..b37babad 100644 --- a/apps/cli/cli_generate.c +++ b/apps/cli/cli_generate.c @@ -65,10 +65,9 @@ /* This is the default callback function. But this is typically overwritten */ #define GENERATE_CALLBACK "cli_set" -#define GENERATE_CALLBACKV "cli_setv" /* variable expand function */ -#define GENERATE_EXPAND_XMLDB "expandv_dbvar" +#define GENERATE_EXPAND_XMLDB "expand_dbvar" /*===================================================================== * YANG generate CLI @@ -154,10 +153,7 @@ cli_callback_generate(clicon_handle h, if (yang2xmlkeyfmt(ys, 0, &xkfmt) < 0) goto done; - if (clicon_option_int(h, "CLICON_CLIGEN_CALLBACK_SINGLE_ARG")==1) - cprintf(cb0, ",%s(\"%s\")", GENERATE_CALLBACK, xkfmt); - else - cprintf(cb0, ",%s(\"%s\")", GENERATE_CALLBACKV, xkfmt); + cprintf(cb0, ",%s(\"%s\")", GENERATE_CALLBACK, xkfmt); retval = 0; done: if (xkfmt) diff --git a/apps/cli/cli_plugin.c b/apps/cli/cli_plugin.c index 4c3f75bf..cbb68cbd 100644 --- a/apps/cli/cli_plugin.c +++ b/apps/cli/cli_plugin.c @@ -372,26 +372,13 @@ cli_load_syntax(clicon_handle h, const char *filename, const char *clispec_dir) } /* Resolve callback names to function pointers. */ - if (clicon_option_int(h, "CLICON_CLIGEN_CALLBACK_SINGLE_ARG")==1){ - if (cligen_callback_str2fn(pt, (cg_str2fn_t*)clixon_str2fn, handle) < 0){ - clicon_err(OE_PLUGIN, 0, "Mismatch between CLIgen file '%s' and CLI plugin file '%s'. Some possible errors:\n\t1. A function given in the CLIgen file does not exist in the plugin (ie link error)\n\t2. The CLIgen spec does not point to the correct plugin .so file (CLICON_PLUGIN=\"%s\" is wrong)", - filename, plgnam, plgnam); - goto done; - } - } - else - if (cligen_callbackv_str2fn(pt, (cgv_str2fn_t*)clixon_str2fn, handle) < 0){ - clicon_err(OE_PLUGIN, 0, "Mismatch between CLIgen file '%s' and CLI plugin file '%s'. Some possible errors:\n\t1. A function given in the CLIgen file does not exist in the plugin (ie link error)\n\t2. The CLIgen spec does not point to the correct plugin .so file (CLICON_PLUGIN=\"%s\" is wrong)", - filename, plgnam, plgnam); - goto done; - } - if (clicon_option_int(h, "CLICON_CLIGEN_EXPAND_SINGLE_ARG")==1){ - if (cligen_expand_str2fn(pt, (expand_str2fn_t*)clixon_str2fn, handle) < 0) - goto done; + if (cligen_callbackv_str2fn(pt, (cgv_str2fn_t*)clixon_str2fn, handle) < 0){ + clicon_err(OE_PLUGIN, 0, "Mismatch between CLIgen file '%s' and CLI plugin file '%s'. Some possible errors:\n\t1. A function given in the CLIgen file does not exist in the plugin (ie link error)\n\t2. The CLIgen spec does not point to the correct plugin .so file (CLICON_PLUGIN=\"%s\" is wrong)", + filename, plgnam, plgnam); + goto done; } - else - if (cligen_expandv_str2fn(pt, (expandv_str2fn_t*)clixon_str2fn, handle) < 0) - goto done; + if (cligen_expandv_str2fn(pt, (expandv_str2fn_t*)clixon_str2fn, handle) < 0) + goto done; /* Make sure we have a syntax mode specified */ if (mode == NULL || strlen(mode) < 1) { /* may be null if not given in file */ diff --git a/apps/cli/cli_show.c b/apps/cli/cli_show.c index fc0f2913..392493f3 100644 --- a/apps/cli/cli_show.c +++ b/apps/cli/cli_show.c @@ -74,9 +74,6 @@ #include "clixon_cli_api.h" #include "cli_common.h" /* internal functions */ -static int xml2csv(FILE *f, cxobj *x, cvec *cvv); -//static int xml2csv_raw(FILE *f, cxobj *x); - /*! Completion callback intended for automatically generated data model * * Returns an expand-type list of commands as used by cligen 'expand' @@ -94,12 +91,12 @@ static int xml2csv(FILE *f, cxobj *x, cvec *cvv); * XXX: helptexts? */ int -expandv_dbvar(void *h, - char *name, - cvec *cvv, - cvec *argv, - cvec *commands, - cvec *helptexts) +expand_dbvar(void *h, + char *name, + cvec *cvv, + cvec *argv, + cvec *commands, + cvec *helptexts) { int retval = -1; char *xkfmt; @@ -197,13 +194,24 @@ expandv_dbvar(void *h, free(xkpath); return retval; } - - - +int +expandv_dbvar(void *h, + char *name, + cvec *cvv, + cvec *argv, + cvec *commands, + cvec *helptexts) +{ + return expand_dbvar(h, name, cvv, argv, commands, helptexts); +} /*! List files in a directory */ int -expand_dir(char *dir, int *nr, char ***commands, mode_t flags, int detail) +expand_dir(char *dir, + int *nr, + char ***commands, + mode_t flags, + int detail) { DIR *dirp; struct dirent *dp; @@ -313,13 +321,11 @@ expand_dir(char *dir, int *nr, char ***commands, mode_t flags, int detail) return retval; } - - /*! CLI callback show yang spec. If arg given matches yang argument string */ int -show_yangv(clicon_handle h, - cvec *cvv, - cvec *argv) +show_yang(clicon_handle h, + cvec *cvv, + cvec *argv) { yang_node *yn; char *str = NULL; @@ -335,362 +341,9 @@ show_yangv(clicon_handle h, yang_print(stdout, yn, 0); return 0; } - - -#ifdef notused -/*! XML to CSV raw variant - * @see xml2csv - */ -static int -xml2csv_raw(FILE *f, cxobj *x) +int show_yangv(clicon_handle h, cvec *vars, cvec *argv) { - cxobj *xc; - cxobj *xb; - int retval = -1; - int i = 0; - - xc = NULL; - while ((xc = xml_child_each(x, xc, CX_ELMNT)) != NULL) { - if (xml_child_nr(xc)){ - xb = xml_child_i(xc, 0); - if (xml_type(xb) == CX_BODY){ - if (i++) - fprintf(f, ";"); - fprintf(f, "%s", xml_value(xb)); - } - } - } - fprintf(f, "\n"); - retval = 0; - return retval; -} -#endif - -/*! Translate XML -> CSV commands - * Can only be made in a 'flat tree', ie on the form: - * B --> - * Type, A - * X, B - * @param[in] f Output file - * @param[in] x XML tree - * @param[in] cvv A vector of field names present in XML - * This means that only fields in x that are listed in cvv will be printed. - */ -static int -xml2csv(FILE *f, cxobj *x, cvec *cvv) -{ - cxobj *xe, *xb; - int retval = -1; - cg_var *vs; - - fprintf(f, "%s", xml_name(x)); - xe = NULL; - - vs = NULL; - while ((vs = cvec_each(cvv, vs))) { - if ((xe = xml_find(x, cv_name_get(vs))) == NULL){ - fprintf(f, ";"); - continue; - } - if (xml_child_nr(xe)){ - xb = xml_child_i(xe, 0); - fprintf(f, ";%s", xml_value(xb)); - } - } - fprintf(f, "\n"); - retval = 0; - return retval; -} - -/*! Generic function for showing configurations. - * Utility function used by cligen spec file - * @param[in] h CLICON handle - * @param[in] cvv Vector of variables from CLIgen command-line - * @param[in] argv A string: [] - * @param[out] xt Configuration as xml tree. - * Format of argv: - * "running", "candidate", "startup" - * xpath expression - * optional name of variable in cvv. If set, xpath must have a '%s' - * @code - * show config id , show_conf_as("running interfaces/interface[name=%s] n"); - * @endcode - */ -static int -show_confv_as(clicon_handle h, - cvec *cvv, - cvec *argv, - cxobj **xt) /* top xml */ -{ - int retval = -1; - char *db; - char *xpath; - char *attr = NULL; - cbuf *cbx = NULL; - int i; - int j; - cg_var *cvattr; - char *val = NULL; - - if (cvec_len(argv) != 2 && cvec_len(argv) != 3){ - if (cvec_len(argv)==1) - clicon_err(OE_PLUGIN, 0, "Got single argument:\"%s\". Expected \",[,]\"", cv_string_get(cvec_i(argv,0))); - else - clicon_err(OE_PLUGIN, 0, "Got %d arguments. Expected: ,[,]", cvec_len(argv)); - - goto done; - } - /* Dont get attr here, take it from arg instead */ - db = cv_string_get(cvec_i(argv, 0)); - if (strcmp(db, "running") != 0 && - strcmp(db, "candidate") != 0 && - strcmp(db, "startup") != 0) { - clicon_err(OE_PLUGIN, 0, "No such db name: %s", db); - goto done; - } - xpath = cv_string_get(cvec_i(argv, 1)); - if ((cbx = cbuf_new()) == NULL){ - clicon_err(OE_PLUGIN, errno, "cbuf_new"); - goto done; - } - if (cvec_len(argv) == 3){ - attr = cv_string_get(cvec_i(argv, 2)); - j = 0; - for (i=0; i [] - * @param[in] netconf If set print as netconf edit-config, otherwise just xml - * @see show_conf_as the main function - */ -static int -show_confv_as_xml1(clicon_handle h, - cvec *cvv, - cvec *argv, - int netconf) -{ - cxobj *xt = NULL; - cxobj *xc; - int retval = -1; - - if (show_confv_as(h, cvv, argv, &xt) < 0) - goto done; - if (netconf) /* netconf prefix */ - fprintf(stdout, "\n"); - xc = NULL; /* Dont print xt itself */ - while ((xc = xml_child_each(xt, xc, -1)) != NULL) - clicon_xml2file(stdout, xc, netconf?2:0, 1); - if (netconf) /* netconf postfix */ - fprintf(stdout, "]]>]]>\n"); - retval = 0; - done: - if (xt) - xml_free(xt); - return retval; -} - -/*! Show configuration as prettyprinted xml - * Utility function used by cligen spec file - * @param[in] h CLICON handle - * @param[in] cvv Vector of variables from CLIgen command-line - * @param[in] arg A string: [] - * @see show_conf_as the main function - */ -int -show_confv_as_xml(clicon_handle h, - cvec *cvv, - cvec *argv) -{ - return show_confv_as_xml1(h, cvv, argv, 0); -} - -/*! Show configuration as prettyprinted xml with netconf hdr/tail - * Utility function used by cligen spec file - * @param[in] h CLICON handle - * @param[in] cvv Vector of variables from CLIgen command-line - * @param[in] arg A string: [] - * @see show_conf_as the main function - */ -int -show_confv_as_netconf(clicon_handle h, - cvec *cvv, - cvec *argv) -{ - return show_confv_as_xml1(h, cvv, argv, 1); -} - -/*! Show configuration as JSON - * Utility function used by cligen spec file - * @param[in] h CLICON handle - * @param[in] cvv Vector of variables from CLIgen command-line - * @param[in] arg A string: [] - * @see show_conf_as the main function - */ -int -show_confv_as_json(clicon_handle h, - cvec *cvv, - cvec *argv) -{ - cxobj *xt = NULL; - int retval = -1; - - if (show_confv_as(h, cvv, argv, &xt) < 0) - goto done; - xml2json(stdout, xt, 1); - retval = 0; - done: - if (xt) - xml_free(xt); - return retval; -} - - -/*! Show configuration as text - * Utility function used by cligen spec file - */ -static int -show_confv_as_text1(clicon_handle h, - cvec *cvv, - cvec *argv) -{ - cxobj *xt = NULL; - cxobj *xc; - int retval = -1; - - if (show_confv_as(h, cvv, argv, &xt) < 0) - goto done; - xc = NULL; /* Dont print xt itself */ - while ((xc = xml_child_each(xt, xc, -1)) != NULL) - xml2txt(stdout, xc, 0); /* tree-formed text */ - retval = 0; - done: - if (xt) - xml_free(xt); - return retval; -} - - -/* Show configuration as commands, ie not tree format but as one-line commands - */ -static int -show_confv_as_command(clicon_handle h, - cvec *cvv, - cvec *argv, - char *prepend) -{ - cxobj *xt = NULL; - cxobj *xc; - enum genmodel_type gt; - int retval = -1; - - if (show_confv_as(h, cvv, argv, &xt) < 0) - goto done; - xc = NULL; /* Dont print xt itself */ - while ((xc = xml_child_each(xt, xc, -1)) != NULL){ - if ((gt = clicon_cli_genmodel_type(h)) == GT_ERR) - goto done; - xml2cli(stdout, xc, prepend, gt); /* cli syntax */ - } - retval = 0; - done: - if (xt) - xml_free(xt); - return retval; -} - -int -show_confv_as_text(clicon_handle h, - cvec *cvv, - cvec *argv) -{ - return show_confv_as_text1(h, cvv, argv); -} - -int -show_confv_as_cli(clicon_handle h, - cvec *cvv, - cvec *argv) -{ - return show_confv_as_command(h, cvv, argv, NULL); /* XXX: how to set prepend? */ -} - -static int -show_confv_as_csv1(clicon_handle h, - cvec *cvv0, - cvec *argv) -{ - cxobj *xt = NULL; - cxobj *xc; - int retval = -1; - cvec *cvv=NULL; - char *str; - - if (show_confv_as(h, cvv0, argv, &xt) < 0) - goto done; - xc = NULL; /* Dont print xt itself */ - while ((xc = xml_child_each(xt, xc, -1)) != NULL){ - if ((str = chunk_sprintf(__FUNCTION__, "%s[]", xml_name(xc))) == NULL) - goto done; -#ifdef NOTYET /* yang-spec? */ - if (ds==NULL && (ds = key2spec_key(dbspec, str)) != NULL){ - cg_var *vs; - fprintf(stdout, "Type"); - cvv = db_spec2cvec(ds); - vs = NULL; - while ((vs = cvec_each(cvv, vs))) - fprintf(stdout, ";%s", cv_name_get(vs)); - fprintf(stdout, "\n"); - } /* Now values just need to follow,... */ -#endif /* yang-spec? */ - if (cvv== NULL) - goto done; - xml2csv(stdout, xc, cvv); /* csv syntax */ - } - retval = 0; - done: - if (xt) - xml_free(xt); - unchunk_group(__FUNCTION__); - return retval; -} - -int -show_confv_as_csv(clicon_handle h, - cvec *cvv, - cvec *argv) -{ - return show_confv_as_csv1(h, cvv, argv); + return show_yang(h, vars, argv); } /*! Generic show configuration CLIGEN callback @@ -704,13 +357,13 @@ show_confv_as_csv(clicon_handle h, * xpath expression, that may contain one %, eg "/sender[name=%s]" * optional name of variable in cvv. If set, xpath must have a '%s' * @code - * show config id , show_conf_as("running","xml","iface[name=%s]","n"); + * show config id , cli_show_config("running","xml","iface[name=%s]","n"); * @endcode */ int -show_configuration(clicon_handle h, - cvec *cvv, - cvec *argv) +cli_show_config(clicon_handle h, + cvec *cvv, + cvec *argv) { int retval = -1; char *db; @@ -824,9 +477,9 @@ done: * @note Hardcoded that a variable in cvv is named "xpath" */ int -show_confv_xpath(clicon_handle h, - cvec *cvv, - cvec *argv) +show_conf_xpath(clicon_handle h, + cvec *cvv, + cvec *argv) { int retval = -1; char *str; @@ -866,417 +519,7 @@ done: xml_free(xt); return retval; } - - -/*================================================================= - * Here are backward compatible cligen callback functions used when - * the option: CLICON_CLIGEN_CALLBACK_SINGLE_ARG is set. - */ - -cb_single_arg(show_yang) - -/*! This is obsolete version of expandv_dbvar - * If CLICON_CLIGEN_EXPAND_SINGLE_ARG is set -*/ -int -expand_dbvar(void *h, - char *name, - cvec *cvv, - cg_var *arg, - int *nr, - char ***commands, - char ***helptexts) +int show_confv_xpath(clicon_handle h, cvec *vars, cvec *argv) { - int nvec; - char **vec = NULL; - int retval = -1; - char *xkfmt; - char *str; - char *dbstr; - cxobj *xt = NULL; - char *xkpath = NULL; - cxobj **xvec = NULL; - size_t xlen = 0; - cxobj *x; - char *bodystr; - int i; - int j; - int k; - int i0; - - if (arg == NULL || (str = cv_string_get(arg)) == NULL){ - clicon_err(OE_PLUGIN, 0, "%s: requires string argument", __FUNCTION__); - goto done; - } - /* In the example, str = "candidate /x/m1/%s/b" */ - if ((vec = clicon_strsep(str, " ", &nvec)) == NULL) - goto done; - dbstr = vec[0]; - if (strcmp(dbstr, "running") != 0 && - strcmp(dbstr, "candidate") != 0 && - strcmp(dbstr, "startup") != 0){ - clicon_err(OE_PLUGIN, 0, "No such db name: %s", dbstr); - goto done; - } - xkfmt = vec[1]; - /* xkfmt = /interface=%s/address=%s - --> /interface=eth0/address=1.2.3.4 - */ - if (xmlkeyfmt2xpath(xkfmt, cvv, &xkpath) < 0) - goto done; - if (clicon_rpc_get_config(h, dbstr, "/", &xt) < 0) - goto done; - if (xpath_vec(xt, xkpath, &xvec, &xlen) < 0) - goto done; - /* One round to detect duplicates - * XXX The code below would benefit from some cleanup - */ - j = 0; - for (i = 0; i < xlen; i++) { - char *str; - x = xvec[i]; - if (xml_type(x) == CX_BODY) - bodystr = xml_value(x); - else - bodystr = xml_body(x); - if (bodystr == NULL){ - clicon_err(OE_CFG, 0, "No xml body"); - goto done; - } - /* detect duplicates */ - for (k=0; k [] - * @param[out] xt Configuration as xml tree. - * Format of arg: - * "running", "candidate", "startup" - * xpath expression - * optional name of variable in cvv. If set, xpath must have a '%s' - * @code - * show config id , show_conf_as("running interfaces/interface[name=%s] n"); - * @endcode - */ -static int -show_conf_as(clicon_handle h, - cvec *cvv, - cg_var *arg, - cxobj **xt) /* top xml */ -{ - int retval = -1; - char *db; - char **vec = NULL; - int nvec; - char *str; - char *xpath; - char *attr = NULL; - cbuf *cbx = NULL; - int i; - int j; - cg_var *cvattr; - char *val = NULL; - - if (arg == NULL || (str = cv_string_get(arg)) == NULL){ - clicon_err(OE_PLUGIN, 0, "%s: requires string argument", __FUNCTION__); - goto done; - } - if ((vec = clicon_strsep(str, " ", &nvec)) == NULL) - goto done; - if (nvec != 2 && nvec != 3){ - clicon_err(OE_PLUGIN, 0, "format error \"%s\" - expected [] got %d arg", str, nvec); - goto done; - } - /* Dont get attr here, take it from arg instead */ - db = vec[0]; - if (strcmp(db, "running") != 0 && - strcmp(db, "candidate") != 0 && - strcmp(db, "startup") != 0) { - clicon_err(OE_PLUGIN, 0, "No such db name: %s", db); - goto done; - } - xpath = vec[1]; - if ((cbx = cbuf_new()) == NULL){ - clicon_err(OE_PLUGIN, errno, "cbuf_new"); - goto done; - } - if (nvec == 3){ - attr = vec[2]; - j = 0; - for (i=0; i [] - * @param[in] netconf If set print as netconf edit-config, otherwise just xml - * @see show_conf_as the main function - */ -static int -show_conf_as_xml1(clicon_handle h, - cvec *cvv, - cg_var *arg, - int netconf) -{ - cxobj *xt = NULL; - cxobj *xc; - int retval = -1; - - if (show_conf_as(h, cvv, arg, &xt) < 0) - goto done; - if (netconf) /* netconf prefix */ - fprintf(stdout, "\n"); - xc = NULL; /* Dont print xt itself */ - while ((xc = xml_child_each(xt, xc, -1)) != NULL) - clicon_xml2file(stdout, xc, netconf?2:0, 1); - if (netconf) /* netconf postfix */ - fprintf(stdout, "]]>]]>\n"); - retval = 0; - done: - if (xt) - xml_free(xt); - return retval; - -} - -/*! Show configuration as prettyprinted xml - * Utility function used by cligen spec file - * @param[in] h CLICON handle - * @param[in] cvv Vector of variables from CLIgen command-line - * @param[in] arg A string: [] - * @see show_conf_as the main function - */ -int -show_conf_as_xml(clicon_handle h, - cvec *cvv, - cg_var *arg) -{ - return show_conf_as_xml1(h, cvv, arg, 0); -} - -/*! Show configuration as prettyprinted xml with netconf hdr/tail - * Utility function used by cligen spec file - * @param[in] h CLICON handle - * @param[in] cvv Vector of variables from CLIgen command-line - * @param[in] arg A string: [] - * @see show_conf_as the main function - */ -int -show_conf_as_netconf(clicon_handle h, - cvec *cvv, - cg_var *arg) -{ - return show_conf_as_xml1(h, cvv, arg, 1); -} - -/*! Show configuration as JSON - * Utility function used by cligen spec file - * @param[in] h CLICON handle - * @param[in] cvv Vector of variables from CLIgen command-line - * @param[in] arg A string: [] - * @see show_conf_as the main function - */ -int -show_conf_as_json(clicon_handle h, - cvec *cvv, - cg_var *arg) -{ - cxobj *xt = NULL; - int retval = -1; - - if (show_conf_as(h, cvv, arg, &xt) < 0) - goto done; - xml2json(stdout, xt, 1); - retval = 0; - done: - if (xt) - xml_free(xt); - return retval; -} - - -/*! Show configuration as text - * Utility function used by cligen spec file - */ -static int -show_conf_as_text1(clicon_handle h, cvec *cvv, cg_var *arg) -{ - cxobj *xt = NULL; - cxobj *xc; - int retval = -1; - - if (show_conf_as(h, cvv, arg, &xt) < 0) - goto done; - xc = NULL; /* Dont print xt itself */ - while ((xc = xml_child_each(xt, xc, -1)) != NULL) - xml2txt(stdout, xc, 0); /* tree-formed text */ - retval = 0; - done: - if (xt) - xml_free(xt); - unchunk_group(__FUNCTION__); - return retval; -} - - -/* Show configuration as commands, ie not tree format but as one-line commands - */ -static int -show_conf_as_command(clicon_handle h, cvec *cvv, cg_var *arg, char *prepend) -{ - cxobj *xt = NULL; - cxobj *xc; - enum genmodel_type gt; - int retval = -1; - - if ((xt = xml_new("tmp", NULL)) == NULL) - goto done; - if (show_conf_as(h, cvv, arg, &xt) < 0) - goto done; - xc = NULL; /* Dont print xt itself */ - while ((xc = xml_child_each(xt, xc, -1)) != NULL){ - if ((gt = clicon_cli_genmodel_type(h)) == GT_ERR) - goto done; - xml2cli(stdout, xc, prepend, gt); /* cli syntax */ - } - retval = 0; - done: - if (xt) - xml_free(xt); - unchunk_group(__FUNCTION__); - return retval; -} - -int -show_conf_as_text(clicon_handle h, cvec *cvv, cg_var *arg) -{ - return show_conf_as_text1(h, cvv, arg); -} - -int -show_conf_as_cli(clicon_handle h, cvec *cvv, cg_var *arg) -{ - return show_conf_as_command(h, cvv, arg, NULL); /* XXX: how to set prepend? */ -} - -static int -show_conf_as_csv1(clicon_handle h, cvec *cvv0, cg_var *arg) -{ - cxobj *xt = NULL; - cxobj *xc; - int retval = -1; - cvec *cvv=NULL; - char *str; - - if (show_conf_as(h, cvv0, arg, &xt) < 0) - goto done; - xc = NULL; /* Dont print xt itself */ - while ((xc = xml_child_each(xt, xc, -1)) != NULL){ - if ((str = chunk_sprintf(__FUNCTION__, "%s[]", xml_name(xc))) == NULL) - goto done; -#ifdef NOTYET /* yang-spec? */ - if (ds==NULL && (ds = key2spec_key(dbspec, str)) != NULL){ - cg_var *vs; - fprintf(stdout, "Type"); - cvv = db_spec2cvec(ds); - vs = NULL; - while ((vs = cvec_each(cvv, vs))) - fprintf(stdout, ";%s", cv_name_get(vs)); - fprintf(stdout, "\n"); - } /* Now values just need to follow,... */ -#endif /* yang-spec? */ - if (cvv== NULL) - goto done; - xml2csv(stdout, xc, cvv); /* csv syntax */ - } - retval = 0; - done: - if (xt) - xml_free(xt); - unchunk_group(__FUNCTION__); - return retval; -} - -int -show_conf_as_csv(clicon_handle h, cvec *cvv, cg_var *arg) -{ - return show_conf_as_csv1(h, cvv, arg); -} - diff --git a/apps/cli/clixon_cli_api.h b/apps/cli/clixon_cli_api.h index 26afcef7..1426a670 100644 --- a/apps/cli/clixon_cli_api.h +++ b/apps/cli/clixon_cli_api.h @@ -74,67 +74,76 @@ int cli_notification_register(clicon_handle h, char *stream, enum format_enum fo #define cli_output cligen_output /* cli_common.c: CLIgen new vector callbacks */ + + +int cli_set(clicon_handle h, cvec *vars, cvec *argv); int cli_setv(clicon_handle h, cvec *vars, cvec *argv); + +int cli_merge(clicon_handle h, cvec *vars, cvec *argv); int cli_mergev(clicon_handle h, cvec *vars, cvec *argv); + +int cli_del(clicon_handle h, cvec *vars, cvec *argv); int cli_delv(clicon_handle h, cvec *vars, cvec *argv); + +int cli_debug_cli(clicon_handle h, cvec *vars, cvec *argv); int cli_debug_cliv(clicon_handle h, cvec *vars, cvec *argv); + +int cli_debug_backend(clicon_handle h, cvec *vars, cvec *argv); int cli_debug_backendv(clicon_handle h, cvec *vars, cvec *argv); + +int cli_set_mode(clicon_handle h, cvec *vars, cvec *argv); int cli_set_modev(clicon_handle h, cvec *vars, cvec *argv); + +int cli_start_shell(clicon_handle h, cvec *vars, cvec *argv); int cli_start_shellv(clicon_handle h, cvec *vars, cvec *argv); + +int cli_quit(clicon_handle h, cvec *vars, cvec *argv); int cli_quitv(clicon_handle h, cvec *vars, cvec *argv); + +int cli_commit(clicon_handle h, cvec *vars, cvec *argv); int cli_commitv(clicon_handle h, cvec *vars, cvec *argv); + +int cli_validate(clicon_handle h, cvec *vars, cvec *argv); int cli_validatev(clicon_handle h, cvec *vars, cvec *argv); + +int compare_dbs(clicon_handle h, cvec *vars, cvec *argv); int compare_dbsv(clicon_handle h, cvec *vars, cvec *argv); + +int load_config_file(clicon_handle h, cvec *vars, cvec *argv); int load_config_filev(clicon_handle h, cvec *vars, cvec *argv); + +int save_config_file(clicon_handle h, cvec *vars, cvec *argv); int save_config_filev(clicon_handle h, cvec *vars, cvec *argv); + +int delete_all(clicon_handle h, cvec *vars, cvec *argv); int delete_allv(clicon_handle h, cvec *vars, cvec *argv); + +int discard_changes(clicon_handle h, cvec *vars, cvec *argv); int discard_changesv(clicon_handle h, cvec *vars, cvec *argv); + +int cli_notify(clicon_handle h, cvec *cvv, cvec *argv); int cli_notifyv(clicon_handle h, cvec *cvv, cvec *argv); + +int db_copy(clicon_handle h, cvec *cvv, cvec *argv); + int cli_lock(clicon_handle h, cvec *cvv, cvec *argv); int cli_unlock(clicon_handle h, cvec *cvv, cvec *argv); -int cli_copy_object(clicon_handle h, cvec *cvv, cvec *argv); - -/* cli_common.c: CLIgen old single arg callbacks */ -int cli_set(clicon_handle h, cvec *vars, cg_var *arg); -int cli_merge(clicon_handle h, cvec *vars, cg_var *arg); -int cli_del(clicon_handle h, cvec *vars, cg_var *arg); -int cli_debug_cli(clicon_handle h, cvec *vars, cg_var *arg); -int cli_debug_backend(clicon_handle h, cvec *vars, cg_var *argv); -int cli_set_mode(clicon_handle h, cvec *vars, cg_var *argv); -int cli_start_shell(clicon_handle h, cvec *vars, cg_var *argv); -int cli_quit(clicon_handle h, cvec *vars, cg_var *arg); -int cli_commit(clicon_handle h, cvec *vars, cg_var *arg); -int cli_validate(clicon_handle h, cvec *vars, cg_var *arg); -int compare_dbs(clicon_handle h, cvec *vars, cg_var *arg); -int load_config_file(clicon_handle h, cvec *vars, cg_var *arg); -int save_config_file(clicon_handle h, cvec *vars, cg_var *arg); -int delete_all(clicon_handle h, cvec *vars, cg_var *arg); -int discard_changes(clicon_handle h, cvec *vars, cg_var *arg); -int cli_notify(clicon_handle h, cvec *cvv, cg_var *arg); +int cli_copy_config(clicon_handle h, cvec *cvv, cvec *argv); /* In cli_show.c */ int expand_dir(char *dir, int *nr, char ***commands, mode_t flags, int detail); +int expand_dbvar(void *h, char *name, cvec *cvv, cvec *argv, + cvec *commands, cvec *helptexts); int expandv_dbvar(void *h, char *name, cvec *cvv, cvec *argv, cvec *commands, cvec *helptexts); + /* cli_show.c: CLIgen new vector arg callbacks */ -int show_confv_as_xml(clicon_handle h, cvec *vars, cvec *argv); -int show_confv_as_netconf(clicon_handle h, cvec *vars, cvec *argv); -int show_confv_as_json(clicon_handle h, cvec *vars, cvec *argv); -int show_confv_as_text(clicon_handle h, cvec *vars, cvec *argv); -int show_confv_as_cli(clicon_handle h, cvec *vars, cvec *argv); -int show_confv_as_csv(clicon_handle h, cvec *vars, cvec *argv); +int show_yang(clicon_handle h, cvec *vars, cvec *argv); int show_yangv(clicon_handle h, cvec *vars, cvec *argv); + +int show_conf_xpath(clicon_handle h, cvec *cvv, cvec *argv); int show_confv_xpath(clicon_handle h, cvec *cvv, cvec *argv); -int show_configuration(clicon_handle h, cvec *cvv, cvec *argv); - -/* cli_show.c: CLIgen old single arg callbacks */ -int show_conf_as_xml(clicon_handle h, cvec *vars, cg_var *arg); -int show_conf_as_netconf(clicon_handle h, cvec *vars, cg_var *arg); -int show_conf_as_json(clicon_handle h, cvec *vars, cg_var *arg); -int show_conf_as_text(clicon_handle h, cvec *vars, cg_var *arg); -int show_conf_as_cli(clicon_handle h, cvec *vars, cg_var *arg); -int show_conf_as_csv(clicon_handle h, cvec *vars, cg_var *arg); -int show_yang(clicon_handle h, cvec *vars, cg_var *arg); +int cli_show_config(clicon_handle h, cvec *cvv, cvec *argv); #endif /* _CLIXON_CLI_API_H_ */ diff --git a/apps/restconf/restconf_main.c b/apps/restconf/restconf_main.c index 74642c82..93936d18 100644 --- a/apps/restconf/restconf_main.c +++ b/apps/restconf/restconf_main.c @@ -112,6 +112,8 @@ api_data(clicon_handle h, retval = api_data_post(h, r, api_path, pcvec, pi, qvec, data); else if (strcmp(request_method, "PUT")==0) retval = api_data_put(h, r, api_path, pcvec, pi, qvec, data); + else if (strcmp(request_method, "PATCH")==0) + retval = api_data_patch(h, r, api_path, pcvec, pi, qvec, data); else if (strcmp(request_method, "DELETE")==0) retval = api_data_delete(h, r, api_path, pi); else @@ -180,7 +182,7 @@ request_process(clicon_handle h, else retval = notfound(r); done: - clicon_debug(1, "%s retval:%d K", __FUNCTION__, retval); + clicon_debug(1, "%s retval:%d", __FUNCTION__, retval); if (pvec) free(pvec); if (dvec) diff --git a/apps/restconf/restconf_methods.c b/apps/restconf/restconf_methods.c index 0b2c5031..5cdb1208 100644 --- a/apps/restconf/restconf_methods.c +++ b/apps/restconf/restconf_methods.c @@ -347,14 +347,14 @@ api_data_edit(clicon_handle h, cbuf *cbx = NULL; cxobj *x; - clicon_debug(1, "%s api_path:%s json:%s", + clicon_debug(1, "%s api_path:\"%s\" json:\"%s\"", __FUNCTION__, api_path, data); for (i=0; iexpandv_dbvar("db","fmt") in all your cli spec files -CLICON_CLIGEN_EXPAND_SINGLE_ARG 0 - -# Set if you want to use old obsolete cligen callback variable syntax -# Migration: Set to 0 and change all user-defined cli callbacks in your cli spec files -# E.g cmd, callback("single arg"); -> cmd, callback("two" "args"); -# And change predefined callbacks, eg cli_commit -> cli_commitv in all cli files -CLICON_CLIGEN_CALLBACK_SINGLE_ARG 1 - - diff --git a/example/routing_cli.cli b/example/routing_cli.cli index 4b0b2342..2b95fca9 100644 --- a/example/routing_cli.cli +++ b/example/routing_cli.cli @@ -4,48 +4,53 @@ CLICON_PROMPT="%U@%H> "; CLICON_PLUGIN="routing_cli"; # Note, when switching to PT, change datamodel to only @datamodel -set @datamodel:ietf-ip, cli_mergev(); +set @datamodel:ietf-ip, cli_merge(); #delete("Delete a configuration item") @datamodel:ietf-ipv4-unicast-routing, cli_del(); -delete("Delete a configuration item") @datamodel:ietf-ip, cli_delv(); +delete("Delete a configuration item") @datamodel:ietf-ip, cli_del(); -validate("Validate changes"), cli_validatev(); -commit("Commit the changes"), cli_commitv(); -quit("Quit Hello"), cli_quitv(); -delete("Delete a configuration item") all("Delete whole candidate configuration"), delete_allv("candidate"); +validate("Validate changes"), cli_validate(); +commit("Commit the changes"), cli_commit(); +quit("Quit Hello"), cli_quit(); +delete("Delete a configuration item") all("Delete whole candidate configuration"), delete_all("candidate"); startup("Store running as startup config"), db_copy("running", "startup"); -no("Negate or remove") debug("Debugging parts of the system"), cli_debug_cliv((int32)0); -debug("Debugging parts of the system"), cli_debug_cliv((int32)1);{ - level("Set debug level: 1..n") ("Set debug level (0..n)"), cli_debug_backendv(); +no("Negate or remove") debug("Debugging parts of the system"), cli_debug_cli((int32)0); +debug("Debugging parts of the system"), cli_debug_cli((int32)1);{ + level("Set debug level: 1..n") ("Set debug level (0..n)"), cli_debug_backend(); } - -discard("Discard edits (rollback 0)"), discard_changesv(); -compare("Compare running and candidate"), compare_dbsv((int32)1); +copy("Copy and create a new object") { + interface("Copy interface"){ + ("name of interface to copy from") to("Copy to interface") ("Name of interface to copy to"), cli_copy_config("candidate","//interface[%s=%s]","name","name","toname"); + } +} +discard("Discard edits (rollback 0)"), discard_changes(); +compare("Compare running and candidate"), compare_dbs((int32)1); +compare("Compare running and candidate"), compare_dbs((int32)1); show("Show a particular state of the system"){ - xpath("Show configuration") ("XPATH expression"), show_confv_xpath("candidate"); - compare("Compare candidate and running databases"), compare_dbsv((int32)0);{ - xml("Show comparison in xml"), compare_dbsv((int32)0); - text("Show comparison in text"), compare_dbsv((int32)1); + xpath("Show configuration") ("XPATH expression"), show_conf_xpath("candidate"); + compare("Compare candidate and running databases"), compare_dbs((int32)0);{ + xml("Show comparison in xml"), compare_dbs((int32)0); + text("Show comparison in text"), compare_dbs((int32)1); } - configuration("Show configuration"), show_confv_as_text("candidate", "/");{ - xml("Show configuration as XML"), show_confv_as_xml("candidate", "/"); - netconf("Show configuration as netconf edit-config operation"), show_confv_as_netconf("candidate", "/"); - text("Show configuration as text"), show_confv_as_text("candidate","/"); - cli("Show configuration as cli commands"), show_confv_as_cli("candidate", "/"); - json("Show configuration as cli commands"), show_confv_as_json("candidate", "/"); + configuration("Show configuration"), cli_show_config("candidate", "text", "/");{ + xml("Show configuration as XML"), cli_show_config("candidate", "xml", "/"); + netconf("Show configuration as netconf edit-config operation"), cli_show_config("candidate", "netconf", "/"); + text("Show configuration as text"), cli_show_config("candidate","text","/"); + cli("Show configuration as cli commands"), cli_show_config("candidate", "cli", "/"); + json("Show configuration as cli commands"), cli_show_config("candidate", "json", "/"); } } -save("Save candidate configuration to XML file") ("Filename (local filename)"), save_config_filev("candidate","filename"); -load("Load configuration from XML file") ("Filename (local filename)"),load_config_filev("filename", "replace");{ - replace("Replace candidate with file contents"), load_config_filev("filename", "replace"); - merge("Merge file with existent candidate"), load_config_filev("filename", "merge"); +save("Save candidate configuration to XML file") ("Filename (local filename)"), save_config_file("candidate","filename"); +load("Load configuration from XML file") ("Filename (local filename)"),load_config_file("filename", "replace");{ + replace("Replace candidate with file contents"), load_config_file("filename", "replace"); + merge("Merge file with existent candidate"), load_config_file("filename", "merge"); } example("This is a comment") ("Just a random number"), mycallback("myarg"); downcall("This is a downcall") , downcall(); -notify("Get notifications from backend"), cli_notifyv("ROUTING", "1", "text"); -no("Negate") notify("Get notifications from backend"), cli_notifyv("ROUTING", "0", "xml"); +notify("Get notifications from backend"), cli_notify("ROUTING", "1", "text"); +no("Negate") notify("Get notifications from backend"), cli_notify("ROUTING", "0", "xml"); lock,cli_lock("candidate"); unlock,cli_unlock("candidate"); \ No newline at end of file diff --git a/lib/src/clixon_proto_client.c b/lib/src/clixon_proto_client.c index 1ed8d5b9..65bbb29e 100644 --- a/lib/src/clixon_proto_client.c +++ b/lib/src/clixon_proto_client.c @@ -220,6 +220,8 @@ clicon_rpc_generate_error(cxobj *xerr) clicon_err_fn("Clixon", 0, OE_XML, 0, "%s", cbuf_get(cb)); retval = 0; done: + if (cb) + cbuf_free(cb); return retval; } diff --git a/lib/src/clixon_xml.c b/lib/src/clixon_xml.c index 7a6f4698..f8134c0e 100644 --- a/lib/src/clixon_xml.c +++ b/lib/src/clixon_xml.c @@ -1479,6 +1479,8 @@ xml_operation(char *opstr, *op = OP_DELETE; else if (strcmp("remove", opstr) == 0) *op = OP_REMOVE; + else if (strcmp("none", opstr) == 0) + *op = OP_NONE; else{ clicon_err(OE_XML, 0, "Bad-attribute operation: %s", opstr); return -1; diff --git a/test/test2.sh b/test/test2.sh index ef16c0cb..0267e87c 100755 --- a/test/test2.sh +++ b/test/test2.sh @@ -47,6 +47,27 @@ expecteof "$clixon_netconf -qf $clixon_cf" "< new "netconf commit" expecteof "$clixon_netconf -qf $clixon_cf" "]]>]]>" "^]]>]]>$" +new "netconf edit config replace" +expecteof "$clixon_netconf -qf $clixon_cf" "eth2ethmerge ]]>]]>" "^]]>]]>$" + +new "netconf get replaced config" +expecteof "$clixon_netconf -qf $clixon_cf" "]]>]]>" "^eth1ethtrueeth2ethtrue]]>]]>$" + +new "netconf edit config create" +expecteof "$clixon_netconf -qf $clixon_cf" 'eth3ethnone ]]>]]>' "^]]>]]>$" + +new "netconf edit config create 2nd" +expecteof "$clixon_netconf -qf $clixon_cf" 'eth3ethmerge ]]>]]>' "^" + +new "netconf edit config delete" +expecteof "$clixon_netconf -qf $clixon_cf" 'eth3ethnone ]]>]]>' "^]]>]]>$" + +new "netconf get delete config" +expecteof "$clixon_netconf -qf $clixon_cf" "]]>]]>" "^eth1ethtrueeth2ethtrue]]>]]>$" + +new "netconf discard-changes" +expecteof "$clixon_netconf -qf $clixon_cf" "]]>]]>" "^]]>]]>$" + new "netconf lock/unlock" expecteof "$clixon_netconf -qf $clixon_cf" "]]>]]>]]>]]>" "^]]>]]>]]>]]>$" diff --git a/test/test3.sh b/test/test3.sh index 82f63b32..0c04bdc6 100755 --- a/test/test3.sh +++ b/test/test3.sh @@ -6,7 +6,7 @@ # kill old backend (if any) new "kill old backend" -#sudo clixon_backend -zf $clixon_cf +sudo clixon_backend -zf $clixon_cf if [ $? -ne 0 ]; then err fi @@ -40,17 +40,22 @@ $' new "restconf head" expectfn "curl -s -I http://localhost/restconf/data" "Content-Type: application/yang.data\+json" -new "restconf patch config" +new "restconf POST config" expectfn 'curl -sX POST -d {"type":"eth"} http://localhost/restconf/data/interfaces/interface=eth4' "" -# XXX POST/PUT/PATCH -new "restconf delete config" +new "restconf DELETE config" expectfn 'curl -sX DELETE http://localhost/restconf/data/interfaces/interface=eth0' "" new "restconf get config" expectfn "curl -sG http://localhost/restconf/data" '{"interfaces": {"interface": \[{"name": "eth1","type": "eth","enabled": "true"},{ "name": "eth4","type": "eth","enabled": "true"}\]}} $' +new "restconf PATCH config" +expectfn 'curl -sX PATCH -d {"type":"eth"} http://localhost/restconf/data/interfaces/interface=eth4' "" + +new "restconf PUT" +expectfn 'curl -sX PUT -d {"type":"eth"} http://localhost/restconf/data/interfaces/interface=eth5' "" + new "Kill restconf daemon" #sudo pkill -u www-data clixon_restconf diff --git a/test/test4.sh b/test/test4.sh new file mode 100755 index 00000000..1c472fbb --- /dev/null +++ b/test/test4.sh @@ -0,0 +1,65 @@ +#!/bin/bash +# Test2: backend and netconf basic functionality + +# include err() and new() functions +. ./lib.sh + +# For memcheck +# clixon_netconf="valgrind --leak-check=full --show-leak-kinds=all clixon_netconf" +clixon_netconf=clixon_netconf + +cat < /tmp/test.yang +module ietf-ip{ + container x { + list y { + key "a b"; + leaf a { + type string; + } + leaf b { + type string; + } + leaf c { + type string; + } + } + leaf d { + type empty; + } + } +} +EOF + +# kill old backend (if any) +new "kill old backend" +sudo clixon_backend -zf $clixon_cf -y /tmp/test +if [ $? -ne 0 ]; then + err +fi + +new "start backend" +# start new backend +sudo clixon_backend -If $clixon_cf -y /tmp/test +if [ $? -ne 0 ]; then + err +fi +new "netconf edit config" +expecteof "$clixon_netconf -qf $clixon_cf -y /tmp/test" "125]]>]]>" "^]]>]]>$" + +new "netconf commit" +expecteof "$clixon_netconf -qf $clixon_cf -y /tmp/test" "]]>]]>" "^]]>]]>$" + +new "netconf get config xpath" +expecteof "$clixon_netconf -qf $clixon_cf -y /tmp/test" "]]>]]>" "^125]]>]]>$" + +new "Kill backend" +# Check if still alive +pid=`pgrep clixon_backend` +if [ -z "$pid" ]; then + err "backend already dead" +fi +# kill backend +sudo clixon_backend -zf $clixon_cf +if [ $? -ne 0 ]; then + err "kill backend" +fi