Exemplo n.º 1
0
/*! Make a notify subscription to backend and un/register callback for return messages.
 * 
 * @param[in] h      Clicon handle
 * @param[in] cvv    Not used
 * @param[in] arg    A string with <log stream name> <stream status> [<format>]
 * where <status> is "0" or "1"
 * and   <format> is XXX
 * Example code: Start logging of mystream and show logs as xml
 * @code
 * cmd("comment"), cli_notify("mystream","1","xml"); 
 * @endcode
 * XXX: format is a memory leak
 */
int
cli_notify(clicon_handle h, 
	   cvec         *cvv, 
	   cvec         *argv)
{
    char            *stream = NULL;
    int              retval = -1;
    int              status;
    char            *formatstr = NULL;
    enum format_enum format = FORMAT_TEXT;

    if (cvec_len(argv) != 2 && cvec_len(argv) != 3){
	clicon_err(OE_PLUGIN, 0, "Requires arguments: <logstream> <status> [<format>]");
	goto done;
    }
    stream = cv_string_get(cvec_i(argv, 0));
    status  = atoi(cv_string_get(cvec_i(argv, 1)));
    if (cvec_len(argv) > 2){
	formatstr = cv_string_get(cvec_i(argv, 2));
	format = format_str2int(formatstr);
    }
    if (cli_notification_register(h, 
				  stream, 
				  format,
				  "", 
				  status, 
				  cli_notification_cb, 
				  (void*)format) < 0)
	goto done;

    retval = 0;
  done:
    return retval;
}
Exemplo n.º 2
0
/*! Copy from one database to another, eg running->startup
 * @param[in] argv  a string: "<db1> <db2>" Copy from db1 to db2
 */
int
db_copy(clicon_handle h, 
	cvec         *cvv, 
	cvec         *argv)
{
    char *db1;
    char *db2;

    db1 = cv_string_get(cvec_i(argv, 0));
    db2 = cv_string_get(cvec_i(argv, 1));
    return clicon_rpc_copy_config(h, db1, db2);
}
Exemplo n.º 3
0
/*! Call expand callback and insert expanded commands in place of variable
 * variable argument callback variant
 * @see pt_expand_fn
 */
static int
pt_expand_fnv(cligen_handle h, 
	      cg_obj       *co,     
	      cvec         *cvv,
	      parse_tree   *ptn,
	      cg_obj       *parent)
{
    int     retval = -1;
    cvec   *commands = cvec_new(0);
    cvec   *helptexts = cvec_new(0);
    cg_var *cv = NULL;
    char   *helpstr;
    cg_obj *con;
    int     i;

    if ((*co->co_expandv_fn)(
			     cligen_userhandle(h)?cligen_userhandle(h):h, 
			     co->co_expand_fn_str, 
			     cvv,
			     co->co_expand_fn_vec,
			     commands, 
			     helptexts) < 0)
	goto done;
    i = 0;
    while ((cv = cvec_each(commands, cv)) != NULL) {
	if (i < cvec_len(helptexts)){
	    helpstr = strdup(cv_string_get(cvec_i(helptexts, i)));
	}
	else
	    helpstr = NULL;
	i++;
	pt_realloc(ptn);
	if (co_expand_sub(co, parent, 
			  &ptn->pt_vec[ptn->pt_len-1]) < 0)
	    goto done;
	con = ptn->pt_vec[ptn->pt_len-1];
	if (transform_var_to_cmd(con, 
				 strdup(cv_string_get(cv)),
				 helpstr) < 0)
	    goto done;
    }
    if (commands)
	cvec_free(commands);
    if (helptexts)
	cvec_free(helptexts);
    retval = 0;
 done:
    return retval;

}
Exemplo n.º 4
0
/*! Change cligen tree
 */
int
changetree(cligen_handle h, cvec *vars, cg_var *arg)
{
    char *treename = cv_string_get(arg);

    return cligen_tree_active_set(h, treename);
}
Exemplo n.º 5
0
/*! Delete all elements in a database 
 * Utility function used by cligen spec file
 */
int
delete_all(clicon_handle h, 
	   cvec         *cvv, 
	   cvec         *argv)
{
    char            *dbstr;
    int              retval = -1;

    if (cvec_len(argv) != 1){
	clicon_err(OE_PLUGIN, 0, "Requires one element: dbname");
	goto done;
    }
    dbstr = cv_string_get(cvec_i(argv, 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;
    }
    if (clicon_rpc_delete_config(h, dbstr) < 0)
	goto done;
    retval = 0;
  done:
    return retval;
}
Exemplo n.º 6
0
/*
 * Command without assigned callback
 */
int
unknown(cligen_handle h, cvec *vars, cg_var *arg)
{
    cg_var *cv = cvec_i(vars, 0);

    printf("The command has no assigned callback: %s\n", cv_string_get(cv));
    return 0;
}
Exemplo n.º 7
0
/*! Start bash from cli callback
 * XXX Application specific??
 * XXX replace fprintf with clicon_err?
 */ 
int
cli_start_shell(clicon_handle h, 
		cvec         *vars, 
		cvec         *argv)
{
    char          *cmd;
    struct passwd *pw;
    int            retval = -1;
    char           bcmd[128];
    cg_var        *cv1 = cvec_i(vars, 1);

    cmd = (cvec_len(vars)>1 ? cv_string_get(cv1) : NULL);

    if ((pw = getpwuid(getuid())) == NULL){
	fprintf(stderr, "%s: getpwuid: %s\n", 
               __FUNCTION__, strerror(errno));
	goto done;
    }
    if (chdir(pw->pw_dir) < 0){
	fprintf(stderr, "%s: chdir(%s): %s\n",
		__FUNCTION__, pw->pw_dir, strerror(errno));
	endpwent();
	goto done;
    }
    endpwent();
    cli_signal_flush(h);
    cli_signal_unblock(h);
    if (cmd){
	snprintf(bcmd, 128, "bash -l -c \"%s\"", cmd);
	if (system(bcmd) < 0){
	    cli_signal_block(h);
	    fprintf(stderr, "%s: system(bash -c): %s\n", 
		    __FUNCTION__, strerror(errno));
	    goto done;
	}
    }
    else
	if (system("bash -l") < 0){
	    cli_signal_block(h);
	    fprintf(stderr, "%s: system(bash): %s\n", 
		    __FUNCTION__, strerror(errno));
	    goto done;
	}
    cli_signal_block(h);
#if 0 /* Allow errcodes from bash */
    if (retval != 0){
	fprintf(stderr, "%s: system(%s) code=%d\n", __FUNCTION__, cmd, retval);
	goto done;
    }
#endif
    retval = 0;
 done:
    return retval;
}
Exemplo n.º 8
0
/*! Set syntax mode
 */
int
cli_set_mode(clicon_handle h, 
	      cvec         *vars, 
	      cvec         *argv)
{
    int     retval = -1;
    char   *str = NULL;

    if (cvec_len(argv) != 1){
	clicon_err(OE_PLUGIN, 0, "Requires one element to be cli mode");
	goto done;
    }
    str = cv_string_get(cvec_i(argv, 0));
    cli_set_syntax_mode(h, str);
    retval = 0;
  done:
    return retval;
}
Exemplo n.º 9
0
/*! Unlock database
 * 
 * @param[in] h      Clicon handle
 * @param[in] cvv    Not used
 * @param[in] arg    A string with <database> 
 * @code
 * lock("comment"), cli_lock("running"); 
 * @endcode
 * XXX: format is a memory leak
 */
int
cli_unlock(clicon_handle h, 
	   cvec         *cvv, 
	   cvec         *argv)
{
    char            *db;
    int              retval = -1;

    if (cvec_len(argv) != 1){
	clicon_err(OE_PLUGIN, 0, "Requires arguments: <db>");
	goto done;
    }
    db = cv_string_get(cvec_i(argv, 0));
    if (clicon_rpc_unlock(h, db) < 0) 
	goto done;
    retval = 0;
  done:
    return retval;
}
Exemplo n.º 10
0
/*
 * This callback changes the prompt to the variable setting
 */
int
secret(cligen_handle h, cvec *vars, cg_var *arg)
{
    printf("This is a hidden command: %s\n", cv_string_get(arg));
    return 0;
}
Exemplo n.º 11
0
/*
 * This callback just prints the function argument
 */
int
hello(cligen_handle h, cvec *vars, cg_var *arg)
{
    printf("%s\n", cv_string_get(arg));
    return 0;
}
Exemplo n.º 12
0
#include "ios.h"

int 
vlan_add_interface(void *handle, cvec *vars, cg_var *arg)
{
    char *dot;
    cg_var *cv;
    cg_var *ifname;
    char *str;

    if ((ifname = cvec_find_var(vars, "name")) == NULL) {
	clicon_err(OE_CFG, ENOENT, "Could not find 'name' in variable vector");
	goto catch;
    }

    dot = strrchr(cv_string_get(ifname), '.');
    *dot = '\0';
	
    if (if_nametoindex(cv_string_get(ifname)) == 0) {
	clicon_err(OE_CFG, ENODEV, "Parent interface '%s'", ifname);
	goto catch;
    }
    *dot = '.';

    /* range check vlan id */
    if (atoi(dot+1) > MAX_VID || atoi(dot+1) < MIN_VID) {
	clicon_err(OE_CFG, ERANGE, "VLAN ID: %s", dot+1);
	goto catch;
    }

    str = chunk_sprintf(__FUNCTION__, 
Exemplo n.º 13
0
/*! Copy database to local file 
 * Utility function used by cligen spec file
 * @param[in] h     CLICON handle
 * @param[in] cvv  variable vector (containing <varname>)
 * @param[in] argv  a string: "<dbname> <varname>" 
 *   <dbname>  is running, candidate, or startup
 *   <varname> is name of cligen variable in the "cvv" vector containing file name
 * Note that "filename" is local on client filesystem not backend.
 * The function can run without a local database
 * @note The file is saved with dummy top-tag: clicon: <clicon></clicon>
 * @code
 *   save file <name:string>, save_config_file("running name");
 * @endcode
 * @see load_config_file
 */
int
save_config_file(clicon_handle h, 
		 cvec         *cvv, 
		 cvec         *argv)
{
    int        retval = -1;
    char      *filename = NULL;
    cg_var    *cv;
    char      *dbstr;
    char      *varstr;
    cxobj     *xt = NULL;
    cxobj     *xerr;
    FILE      *f = NULL;

    if (cvec_len(argv) != 2){
	if (cvec_len(argv)==1)
	    clicon_err(OE_PLUGIN, 0, "Got single argument:\"%s\". Expected \"<dbname>,<varname>\"",
		       cv_string_get(cvec_i(argv,0)));
	else
	    clicon_err(OE_PLUGIN, 0, " Got %d arguments. Expected: <dbname>,<varname>",
		       cvec_len(argv));

	goto done;
    }
    dbstr = cv_string_get(cvec_i(argv, 0));
    varstr  = cv_string_get(cvec_i(argv, 1));
    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;
    }
    if ((cv = cvec_find(cvv, varstr)) == NULL){
	clicon_err(OE_PLUGIN, 0, "No such var name: %s", varstr);	
	goto done;
    }
    filename = cv_string_get(cv);
    if (clicon_rpc_get_config(h, dbstr,"/", &xt) < 0)
	goto done;
    if (xt == NULL){
	clicon_err(OE_CFG, 0, "get config: empty tree"); /* Shouldnt happen */
	goto done;
    }
    if ((xerr = xpath_first(xt, "/rpc-error")) != NULL){
	clicon_rpc_generate_error("Get configuration", xerr);
	goto done;
    }
    /* get-config returns a <data> tree. Save as <config> tree so it can be used
     * as data-store.
     */
    if (xml_name_set(xt, "config") < 0)
	goto done;
    if ((f = fopen(filename, "w")) == NULL){
	clicon_err(OE_CFG, errno, "Creating file %s", filename);
	goto done;
    } 
    if (clicon_xml2file(f, xt, 0, 1) < 0)
	goto done;
    retval = 0;
    /* Fall through */
  done:
    if (xt)
	xml_free(xt);
    if (f != NULL)
	fclose(f);
    return retval;
}
Exemplo n.º 14
0
/*! Load a configuration file to candidate database
 * Utility function used by cligen spec file
 * @param[in] h     CLICON handle
 * @param[in] cvv   Vector of variables (where <varname> is found)
 * @param[in] argv  A string: "<varname> (merge|replace)" 
 *   <varname> is name of a variable occuring in "cvv" containing filename
 * @note that "filename" is local on client filesystem not backend. 
 * @note file is assumed to have a dummy top-tag, eg <clicon></clicon>
 * @code
 *   # cligen spec
 *   load file <name2:string>, load_config_file("name2","merge");
 * @endcode
 * @see save_config_file
 */
int 
load_config_file(clicon_handle h, 
		 cvec         *cvv, 
		 cvec         *argv)
{
    int         ret = -1;
    struct stat st;
    char       *filename = NULL;
    int         replace;
    cg_var     *cv;
    char       *opstr;
    char       *varstr;
    int         fd = -1;
    cxobj      *xt = NULL;
    cxobj      *x;
    cbuf       *cbxml;

    if (cvec_len(argv) != 2){
	if (cvec_len(argv)==1)
	    clicon_err(OE_PLUGIN, 0, "Got single argument:\"%s\". Expected \"<varname>,<op>\"", cv_string_get(cvec_i(argv,0)));
	else
	    clicon_err(OE_PLUGIN, 0, "Got %d arguments. Expected: <varname>,<op>", cvec_len(argv));
	goto done;
    }
    varstr = cv_string_get(cvec_i(argv, 0));
    opstr  = cv_string_get(cvec_i(argv, 1));
    if (strcmp(opstr, "merge") == 0) 
	replace = 0;
    else if (strcmp(opstr, "replace") == 0) 
	replace = 1;
    else{
	clicon_err(OE_PLUGIN, 0, "No such op: %s, expected merge or replace", opstr);	
	goto done;
    }
    if ((cv = cvec_find(cvv, varstr)) == NULL){
	clicon_err(OE_PLUGIN, 0, "No such var name: %s", varstr);	
	goto done;
    }
    filename = cv_string_get(cv);
    if (stat(filename, &st) < 0){
 	clicon_err(OE_UNIX, 0, "load_config: stat(%s): %s", 
		   filename, strerror(errno));
	goto done;
    }
    /* Open and parse local file into xml */
    if ((fd = open(filename, O_RDONLY)) < 0){
	clicon_err(OE_UNIX, errno, "open(%s)", filename);
	goto done;
    }
    if (xml_parse_file(fd, "</clicon>", NULL, &xt) < 0)
	goto done;
    if (xt == NULL)
	goto done;
    if ((cbxml = cbuf_new()) == NULL)
	goto done;
    x = NULL;
    while ((x = xml_child_each(xt, x, -1)) != NULL) {
	/* Ensure top-level is "config", maybe this is too rough? */
	xml_name_set(x, "config");
	if (clicon_xml2cbuf(cbxml, x, 0, 0) < 0)
	    goto done;
    }
    if (clicon_rpc_edit_config(h, "candidate",
			       replace?OP_REPLACE:OP_MERGE, 
			       cbuf_get(cbxml)) < 0)
	goto done;
    cbuf_free(cbxml);
    //    }
    ret = 0;
 done:
    if (xt)
	xml_free(xt);
    if (fd != -1)
	close(fd);
    return ret;
}
Exemplo n.º 15
0
/*! 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 
 * @param[in]  argv Vector. First element xml key format string, eg "/aaa/%s"
 * @param[in]  op   Operation to perform on database
 * Cvv will contain first the complete cli string, and then a set of optional
 * instantiated variables.
 * Example:
 * cvv[0]  = "set interfaces interface eth0 type bgp"
 * cvv[1]  = "eth0"
 * cvv[2]  = "bgp"
 * argv[0] = "/interfaces/interface/%s/type"
 * op: OP_MERGE
 * @see cli_callback_generate where arg is generated
 */
static int
cli_dbxml(clicon_handle       h, 
	  cvec               *cvv, 
	  cvec               *argv, 
	  enum operation_type op)
{
    int        retval = -1;
    char      *str = NULL;
    char      *api_path_fmt;  /* xml key format */
    char      *api_path = NULL; /* xml key */
    cg_var    *cval;
    int        len;
    cg_var    *arg;
    cbuf      *cb = NULL;
    yang_stmt *yspec;
    cxobj     *xbot = NULL; /* xpath, NULL if datastore */
    yang_stmt *y = NULL; /* yang spec of xpath */
    cxobj     *xtop = NULL; /* xpath root */
    cxobj     *xa;           /* attribute */
    cxobj     *xb;           /* body */

    if (cvec_len(argv) != 1){
	clicon_err(OE_PLUGIN, 0, "Requires one element to be xml key format string");
	goto done;
    }
    if ((yspec = clicon_dbspec_yang(h)) == NULL){
	clicon_err(OE_FATAL, 0, "No DB_SPEC");
	goto done;
    }
    arg = cvec_i(argv, 0);
    api_path_fmt = cv_string_get(arg);
    if (api_path_fmt2api_path(api_path_fmt, cvv, &api_path) < 0)
	goto done;
    /* Create config top-of-tree */
    if ((xtop = xml_new("config", NULL, NULL)) == NULL)
	goto done;
    xbot = xtop;
    if (api_path && api_path2xml(api_path, yspec, xtop, YC_DATANODE, 1, &xbot, &y) < 1)
	goto done; 
    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)
	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 ((cb = cbuf_new()) == NULL){
	clicon_err(OE_XML, errno, "cbuf_new");
	goto done;
    }
    if (clicon_xml2cbuf(cb, xtop, 0, 0) < 0)
	goto done;
    if (clicon_rpc_edit_config(h, "candidate", OP_NONE, cbuf_get(cb)) < 0)
	goto done;
    if (clicon_autocommit(h)) {
	if (clicon_rpc_commit(h) < 0) 
	    goto done;
    }
    retval = 0;
 done:
    if (cb)
	cbuf_free(cb);
    if (str)
	free(str);
    if (api_path)
	free(api_path);  
    if (xtop)
	xml_free(xtop);
    return retval;
}
Exemplo n.º 16
0
/*! Copy one configuration object to antother
 *
 * Works for objects that are items ina yang list with a keyname, eg as:
 *   list sender{ 
 *      key name;	
 *	leaf name{...
 *
 * @param[in]  h    CLICON handle
 * @param[in]  cvv  Vector of variables from CLIgen command-line
 * @param[in]  argv Vector: <db>, <xpath>, <field>, <fromvar>, <tovar>
 * Explanation of argv fields:
 *  db:     Database name, eg candidate|tmp|startup
 *  xpath:  XPATH expression with exactly two %s pointing to field and from name
 *  field:  Name of list key, eg name
 *  fromvar:Name of variable containing name of object to copy from (given by xpath)
 *  tovar:  Name of variable containing name of object to copy to.
 * @code
 * cli spec:
 *  copy snd <n1:string> to <n2:string>, cli_copy_config("candidate", "/sender[%s='%s']", "from", "n1", "n2");
 * cli command:
 *  copy snd from to to
 * @endcode
 */
int
cli_copy_config(clicon_handle h, 
		cvec         *cvv, 
		cvec         *argv)
{
    int          retval = -1;
    char        *db;
    cxobj       *x1 = NULL; 
    cxobj       *x2 = NULL; 
    cxobj       *x;
    char        *xpath;
    int          i;
    int          j;
    cbuf        *cb = NULL;
    char        *keyname;
    char        *fromvar;
    cg_var      *fromcv;
    char        *fromname = NULL;
    char        *tovar;
    cg_var      *tocv;
    char        *toname;
    cxobj       *xerr;

    if (cvec_len(argv) != 5){
	clicon_err(OE_PLUGIN, 0, "Requires four elements: <db> <xpath> <keyname> <from> <to>");
	goto done;
    }
    /* First argv argument: Database */
    db = cv_string_get(cvec_i(argv, 0));
    /* Second argv argument: xpath */
    xpath = cv_string_get(cvec_i(argv, 1));
    /* Third argv argument: name of keyname */
    keyname = cv_string_get(cvec_i(argv, 2));
    /* Fourth argv argument: from variable */
    fromvar = cv_string_get(cvec_i(argv, 3));
    /* Fifth argv argument: to variable */
    tovar = cv_string_get(cvec_i(argv, 4));
    
    /* Get from variable -> cv -> from name */
    if ((fromcv = cvec_find(cvv, fromvar)) == NULL){
	clicon_err(OE_PLUGIN, 0, "fromvar '%s' not found in cligen var list", fromvar);	
	goto done;
    }
    /* Get from name from cv */
    fromname = cv_string_get(fromcv);
    /* Create xpath */
    if ((cb = cbuf_new()) == NULL){
	clicon_err(OE_PLUGIN, errno, "cbuf_new");	
	goto done;
    }
    /* Sanity check that xpath contains exactly two %s, ie [%s='%s'] */
    j = 0;
    for (i=0; i<strlen(xpath); i++){
	if (xpath[i] == '%')
	    j++;
    }
    if (j != 2){
	clicon_err(OE_PLUGIN, 0, "xpath '%s' does not have two '%%'", xpath);	
	goto done;
    }
    cprintf(cb, xpath, keyname, fromname);	
    /* Get from object configuration and store in x1 */
    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("Get configuration", xerr);
	goto done;
    }

    /* Get to variable -> cv -> to name */
    if ((tocv = cvec_find(cvv, tovar)) == NULL){
	clicon_err(OE_PLUGIN, 0, "tovar '%s' not found in cligen var list", tovar);
	goto done;
    }
    toname = cv_string_get(tocv);
    /* Create copy xml tree x2 */
    if ((x2 = xml_new("new", NULL, NULL)) == NULL)
	goto done;
    if (xml_copy(x1, x2) < 0)
	goto done;
    xml_name_set(x2, "config");
    cprintf(cb, "/%s", keyname);	
    if ((x = xpath_first(x2, "%s", cbuf_get(cb))) == NULL){
	clicon_err(OE_PLUGIN, 0, "Field %s not found in copy tree", keyname);
	goto done;
    }
    x = xml_find(x, "body");
    xml_value_set(x, toname);
    /* resuse cb */
    cbuf_reset(cb);
    /* create xml copy tree and merge it with database configuration */
    clicon_xml2cbuf(cb, x2, 0, 0);
    if (clicon_rpc_edit_config(h, db, OP_MERGE, cbuf_get(cb)) < 0)
	goto done;
    retval = 0;
 done:
    if (cb)
	cbuf_free(cb);
    if (x1 != NULL)
	xml_free(x1);
    if (x2 != NULL)
	xml_free(x2);
    return retval;
}