예제 #1
0
static int command_userlogcleanup(struct plugin_handle* plugin, struct plugin_user* user, struct plugin_command* cmd)
{
	struct log_data* ldata = (struct log_data*) plugin->ptr;
	struct cbuffer* buf = cbuf_create(128);
	struct plugin_command_arg_data* arg = (struct plugin_command_arg_data*) list_get_first(cmd->args);
	
	int days = arg->data.integer;

	int rc = sql_execute(ldata, null_callback, NULL, "DELETE FROM userlog WHERE time < DATETIME('NOW', 'localtime', '-%d days');", days);
	
	if (rc > 0)
		cbuf_append_format(buf, "*** %s: Cleaned log entries older than %d days.", cmd->prefix, days);
	else
		cbuf_append_format(buf, "*** %s: Unable to clean log table.", cmd->prefix);
  
	plugin->hub.send_message(plugin, user, cbuf_get(buf));
	cbuf_destroy(buf);

	sql_execute(ldata, null_callback, NULL, "VACUUM;");

	return 0;
}
예제 #2
0
/*! Generic xml netconf clicon rpc
 * Want to go over to use netconf directly between client and server,...
 * @param[in]  h       clicon handle
 * @param[in]  xml     XML netconf tree 
 * @param[out] xret    Return XML netconf tree, error or OK
 * @param[out] sp      Socket pointer for notification, otherwise NULL
 * @code
 *   cxobj *xret = NULL;
 *   int    s; 
 *   if (clicon_rpc_netconf_xml(h, x, &xret, &s) < 0)
 *	err;
 *   xml_free(xret);
 * @endcode

 * @see clicon_rpc_netconf xml as string instead of tree
 */
int
clicon_rpc_netconf_xml(clicon_handle  h, 
		       cxobj         *xml,
		       cxobj        **xret,
		       int           *sp)
{
    int                retval = -1;
    cbuf               *cb = NULL;

    if ((cb = cbuf_new()) == NULL){
	clicon_err(OE_XML, errno, "cbuf_new");
	goto done;
    }
    if (clicon_xml2cbuf(cb, xml, 0, 0) < 0)
	goto done;
    if (clicon_rpc_netconf(h, cbuf_get(cb), xret, sp) < 0)
	goto done;
    retval = 0;
 done:
    if (cb)
	cbuf_free(cb);
    return retval;
}
예제 #3
0
/**
 * The callback function for handling the !history command.
 */
static int command_history(struct plugin_handle* plugin, struct plugin_user* user, struct plugin_command* cmd)
{
	struct cbuffer* buf;
	struct chat_history_data* data = (struct chat_history_data*) plugin->ptr;
	struct plugin_command_arg_data* arg = plugin->hub.command_arg_next(plugin, cmd, plugin_cmd_arg_type_integer);
	int maxlines;

	if (!list_size(data->chat_history))
		return command_status(plugin, user, cmd, cbuf_create_const("No messages."));

	if (arg)
		maxlines = arg->data.integer;
	else
		maxlines = data->history_default;
	
	buf = cbuf_create(MAX_HISTORY_SIZE);
	cbuf_append_format(buf, "*** %s: Chat History:\n", cmd->prefix);
	get_messages(data, maxlines, buf);

	plugin->hub.send_message(plugin, user, cbuf_get(buf));
	cbuf_destroy(buf);
	return 0;
}
예제 #4
0
파일: mod_extras.c 프로젝트: mimicmod/uhub
static int command_releaseadd(struct plugin_handle* plugin, struct plugin_user* user, struct plugin_command* cmd)
{
	struct extras_data* extrasdata = (struct extras_data*) plugin->ptr;
	struct cbuffer* buf = cbuf_create(128);
	struct plugin_command_arg_data* arg1 = (struct plugin_command_arg_data*) list_get_first(cmd->args);
	struct plugin_command_arg_data* arg2 = (struct plugin_command_arg_data*) list_get_next(cmd->args);

	char* tth = strdup(sql_escape_string(arg1->data.string));
	char* title = strdup(sql_escape_string(arg2->data.string));
  
	int rc = sql_execute(extrasdata, null_callback, NULL, "INSERT INTO releases (id, title, tth) VALUES(NULL, '%s', '%s');", title, tth);
  
	if (rc > 0)
		cbuf_append_format(buf, "*** %s: Added \"%s\" to releases.", cmd->prefix, title);
	else
		cbuf_append_format(buf, "*** %s: Unable to add \"%s\" to releases.", cmd->prefix, title);
  
	plugin->hub.send_message(plugin, user, cbuf_get(buf));
	cbuf_destroy(buf);
	hub_free(tth);
	hub_free(title);

	return 0;
}
예제 #5
0
static int command_userlog(struct plugin_handle* plugin, struct plugin_user* user, struct plugin_command* cmd)
{
	struct log_data* ldata = (struct log_data*) plugin->ptr;
	struct cbuffer* buf = cbuf_create(128);
	size_t argnum = list_size(cmd->args);
	struct plugin_command_arg_data* arg1 = NULL;
	struct plugin_command_arg_data* arg2 = NULL;
	struct plugin_command_arg_data* arg3 = NULL;
	
	if (argnum == 3)
	{
		arg1 = plugin->hub.command_arg_next(plugin, cmd, plugin_cmd_arg_type_integer);
		arg2 = plugin->hub.command_arg_next(plugin, cmd, plugin_cmd_arg_type_string);
		arg3 = plugin->hub.command_arg_next(plugin, cmd, plugin_cmd_arg_type_string);
	}
	else
	{
		if (argnum == 2)
		{
			cbuf_append_format(buf, "*** %s: Missing search pattern.", cmd->prefix);
			plugin->hub.send_message(plugin, user, cbuf_get(buf));
			cbuf_destroy(buf);
			return 0;
		}
		if (argnum == 1)
			arg1 = plugin->hub.command_arg_next(plugin, cmd, plugin_cmd_arg_type_integer);
	}

	int lines = arg1 ? arg1->data.integer : 20;
	char* column = arg2 ? arg2->data.string : "";
	char* search = arg3 ? arg3->data.string : "";
	size_t column_len = strlen(column);
	size_t search_len = strlen(search);
	char query[1024];
	sqlite3_stmt *res;
	int error = 0;
	const char *tail;
	size_t count = 0;

	if (lines > 200)
		lines = 200;

	if (search_len && column_len)
	{
		if(!check_column(column))
		{
			cbuf_append_format(buf, "*** %s: Invalid column. Valid columns are: nick, cid, addr, credentials, useragent, message, all.", cmd->prefix);
			plugin->hub.send_message(plugin, user, cbuf_get(buf));
			cbuf_destroy(buf);
			return 0;
		}

		if (strcmp(column, "all") == 0)
		{
			sprintf(query, "SELECT * FROM userlog WHERE nick LIKE '%%%s%%' OR cid LIKE '%%%s%%' OR credentials LIKE '%%%s%%' OR useragent LIKE '%%%s%%' OR addr LIKE '%%%s%%' OR message LIKE '%%%s%%' ORDER BY time DESC LIMIT %d;", search, search, search, search, search, search, lines);
			cbuf_append_format(buf, "*** %s: Search_ing for \"%s\" in all columns.", cmd->prefix, search);
		}
		else
		{
			sprintf(query, "SELECT * FROM userlog WHERE %s LIKE '%%%s%%' ORDER BY time DESC LIMIT %d;", column, search, lines);
			cbuf_append_format(buf, "*** %s: Searching for \"%s\" in column \"%s\".", cmd->prefix, search, column);
		}
	}
	else
	{
		sprintf(query, "SELECT * FROM userlog ORDER BY time DESC LIMIT %d;", lines);
		cbuf_append_format(buf, "*** %s: ", cmd->prefix);
	}

	error = sqlite3_prepare_v2(ldata->db, query, strlen(query), &res, &tail);
    
	while (sqlite3_step(res) == SQLITE_ROW)
	{
		cbuf_append_format(buf, "\n[%s] %s, %s [%s] [%s] \"%s\" - %s", (char*) sqlite3_column_text(res, 6), (char*) sqlite3_column_text(res, 1), (char*) sqlite3_column_text(res, 0), (char*) sqlite3_column_text(res, 3), (char*) sqlite3_column_text(res, 2), (char*) sqlite3_column_text(res, 4), (char*) sqlite3_column_text(res, 5));
		count++;
	}

	if (error || count == 0)
	{
		if (search_len && column_len)
			cbuf_append(buf, "\n");
		cbuf_append(buf, "No log entries found.");
	}
	else
		cbuf_append_format(buf, "\n\n%zd entr%s shown", count, count != 1 ? "ies" : "y");

	sqlite3_finalize(res);
  
	plugin->hub.send_message(plugin, user, cbuf_get(buf));
	cbuf_destroy(buf);
    
	return 0;
}
예제 #6
0
int main(void)
{
	CircBuf *cbuf;
	unsigned long val, val2;
	unsigned long vals[32];
	unsigned char c, c2;
	unsigned char s[10];
	int i, j;

	cbuf = cbuf_new(sizeof(val), 32);
	
	assert(cbuf != NULL);
	assert(cbuf->size == (sizeof(val) * 32));
	assert(cbuf_unread(cbuf) == 0);
	assert(cbuf_unwritten(cbuf) == 31);

	val = 0xaaaaaaaa;
	cbuf_put(cbuf, &val, 1);

	/* 
	 * Note:  unread() + unwritten() should always equal 31
	 * (one less than the size of the buffer)
	 */
	assert(cbuf_unread(cbuf) == 1);
	assert(cbuf_unwritten(cbuf) == 30);

	cbuf_peek(cbuf, 0, &val2, 1);
	
	assert(val2 == val);
	assert(cbuf_unread(cbuf) == 1);
	assert(cbuf_unwritten(cbuf) == 30);

	val = 0xdeadbeef;
	cbuf_put(cbuf, &val, 1);
	assert(cbuf_unread(cbuf) == 2);
	assert(cbuf_unwritten(cbuf) == 29);

	val2 = 0;
	cbuf_get(cbuf, &val2, 1);
	assert(val2 == 0xaaaaaaaa);
	assert(cbuf_unread(cbuf) == 1);
	assert(cbuf_unwritten(cbuf) == 30);

	val = 0xdeadbabe;
	cbuf_put(cbuf, &val, 1);
	val = 0x12345678;
	cbuf_put(cbuf, &val, 1);

	/* Write 10 elements */
	for (i = 0; i < 10; i++)
		vals[i] = i;
	cbuf_put(cbuf, vals, 10);

	assert(cbuf_unread(cbuf) == 13);
	assert(cbuf_unwritten(cbuf) == 18);

	val2 = 0;
	cbuf_get(cbuf, &val2, 1);
	assert(val2 == 0xdeadbeef);
	cbuf_get(cbuf, &val2, 1);
	assert(val2 == 0xdeadbabe);
	
	/* 
	 * Now let's try writing across the boundary.. we've written
	 * a total of 14 elements so far.  So let's write 18 now
	 * to make sure we're overwriting the first things we wrote.
	 */
	for (i = 0; i < 18; i++)
		vals[i] = 0xFFFF0000 | i;
	cbuf_put(cbuf, vals, 18);

	assert(cbuf_unread(cbuf) == 29);
	assert(cbuf_unwritten(cbuf) == 2);

	cbuf_get(cbuf, &val2, 1);
	assert(val2 == 0x12345678);

	cbuf_get(cbuf, vals, 10);
	for (i = 0; i < 10; i++)
		assert(vals[i] == i);
	assert(cbuf_unread(cbuf) == 18);
	assert(cbuf_unwritten(cbuf) == 13);

	/* Now read across boundary */
	cbuf_get(cbuf, vals, 18);
	for (i = 0; i < 18; i++)
		assert(vals[i] == (0xFFFF0000 | i));
	assert(cbuf_unread(cbuf) == 0);
	assert(cbuf_unwritten(cbuf) == 31);

	/* One more boundary test, writing 1 element at a time */
	for (i = 0; i < 31; i++) {
		val = (0xaaaa0000 | i);
		cbuf_put(cbuf, &val, 1);
	}

	assert(cbuf_unread(cbuf) == 31);
	assert(cbuf_unwritten(cbuf) == 0);

	for (i = 0; i < 31; i++) {
		cbuf_get(cbuf, &val, 1);
		assert(val == (0xaaaa0000 | i));
	}

	assert(cbuf_unread(cbuf) == 0);
	assert(cbuf_unwritten(cbuf) == 31);

	cbuf_destroy(cbuf);

	/* Test with character elements instead of longs */
	cbuf = cbuf_new(sizeof(c), 10);
	
	assert(cbuf != NULL);
	assert(cbuf->size == (sizeof(c) * 10));
	assert(cbuf_unread(cbuf) == 0);
	assert(cbuf_unwritten(cbuf) == 9);

	c = '@';
	cbuf_put(cbuf, &c, 1);

	assert(cbuf_unread(cbuf) == 1);
	assert(cbuf_unwritten(cbuf) == 8);

	cbuf_peek(cbuf, 0, &c2, 1);
	
	assert(c2 == c);
	assert(cbuf_unread(cbuf) == 1);
	assert(cbuf_unwritten(cbuf) == 8);

	c = 'a';
	cbuf_put(cbuf, &c, 1);
	assert(cbuf_unread(cbuf) == 2);
	assert(cbuf_unwritten(cbuf) == 7);

	c2 = '\0';
	cbuf_get(cbuf, &c2, 1);
	assert(c2 == '@');
	assert(cbuf_unread(cbuf) == 1);
	assert(cbuf_unwritten(cbuf) == 8);

	c = 'b';
	cbuf_put(cbuf, &c, 1);
	c = '#';
	cbuf_put(cbuf, &c, 1);

	cbuf_get(cbuf, &c, 1);
	assert(c == 'a');
	cbuf_get(cbuf, &c, 1);
	assert(c == 'b');

	assert(cbuf_unread(cbuf) == 1);
	assert(cbuf_unwritten(cbuf) == 8);

	/* Write 8 elements */
	for (i = 0; i < 8; i++)
		s[i] = (unsigned char) i;
	cbuf_put(cbuf, s, 8);

	assert(cbuf_unwritten(cbuf) == 0);
	assert(cbuf_unread(cbuf) == 9);

	c = '\0';
	cbuf_get(cbuf, &c, 1);
	assert(c == '#');

	for (i = 0; i < 8; i++)
		s[i] = '0';

	cbuf_get(cbuf, s, 8);
	for (i = 0; i < 8; i++)
		assert(s[i] == (unsigned char) i);


	assert(cbuf_unread(cbuf) == 0);
	assert(cbuf_unwritten(cbuf) == 9);

	cbuf_destroy(cbuf);	

	printf("Unit test PASSED\n");
	return 0;
}
예제 #7
0
파일: cli_common.c 프로젝트: clicon/clixon
/*! 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;
}
예제 #8
0
파일: cli_common.c 프로젝트: clicon/clixon
/*! 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;
}
예제 #9
0
파일: cli_common.c 프로젝트: clicon/clixon
/*! 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;
}