void test_copy (void) { char str1[] = "\x01\x01x\x01\x01y\x01\x01xy\x01\x01"; char *str2 = (char *)NULL; char *str3 = (char *)NULL; cbuffer_t *buf1 = (cbuffer_t *)NULL; cbuffer_t *buf2 = (cbuffer_t *)NULL; buf1 = cbuf_new(); buf2 = cbuf_new(); cbuf_import (buf1, str1, strlen (str1)); cbuf_copy (buf2, buf1); printf ("test_copy(): str1 = %s\n", str1); str2 = (char *)xmalloc (buf1->sz + 1); memset (str2, (int)NULL, buf1->sz + 1); memcpy (str2, buf1->data, buf1->sz); str3 = (char *)xmalloc (buf2->sz + 1); memset (str3, (int)NULL, buf2->sz + 1); memcpy (str3, buf2->data, buf2->sz); printf ("test_copy(): str2 = %s\ntest_copy(): str3 = %s\n", str2, str3); xfree (str2); xfree (str3); cbuf_delete (buf1); cbuf_delete (buf2); }
void test_split (void) { char str0[] = "\x01"; char str1[] = "\x01\x01x\x01y\x01z\x01xy\x01yz"; char str2[] = "buffer one\n\x01\x02\nend buffer\n"; char str3[] = "buffer two\n\x01\x02\nend buffer\n"; deque_t *split = (deque_t *)NULL; cbuffer_t *buf1 = (cbuffer_t *)NULL; cbuffer_t *buf2 = (cbuffer_t *)NULL; cbuffer_t *buf3 = (cbuffer_t *)NULL; buf1 = cbuf_new (); buf2 = cbuf_new (); buf3 = cbuf_new (); cbuf_import (buf1, str1, strlen (str1)); cbuf_import (buf2, str2, strlen (str2)); cbuf_import (buf3, str3, strlen (str3)); split = cbuf_split (buf1, (void *)str0, 1); printf ("test_split(): len = %d\n", deque_length (split)); deque_push (split, buf2); printf ("test_split(): len = %d\n", deque_length (split)); deque_push (split, buf3); printf ("test_split(): len = %d\n", deque_length (split)); cbuf_delete (buf1); deque_delete (split, cbuf_delete_callback); }
struct reg_parse* reg_parse_new(const void* ctx, struct reg_parse_callback cb, const char* str_enc, unsigned flags) { struct reg_parse* s = talloc_zero(ctx, struct reg_parse); if (s == NULL) return NULL; s->key = cbuf_new(s); s->valname = cbuf_new(s); s->valblob = cbuf_new(s); s->tmp = cbuf_new(s); if ( (s->tmp == NULL) || (s->valblob == NULL) || (s->valname == NULL) || (s->key == NULL) ) { goto fail; } s->reg_format_callback.writeline = (reg_format_callback_writeline_t)®_parse_line; s->reg_format_callback.data = s; s->valtype = 0; if (cb.key == NULL) { cb.key = (reg_parse_callback_key_t)&nop; } if (cb.val == NULL) { cb.val = (reg_parse_callback_val_t)&nop; } if (cb.val_del == NULL) { cb.val_del = (reg_parse_callback_val_del_t)&nop; } if (cb.comment == NULL) { cb.comment = (reg_parse_callback_comment_t)&nop; } s->call = cb; s->linenum = 0; s->state = STATE_DEFAULT; s->flags = flags; if (str_enc && !set_iconv(&s->str2UTF16, "UTF-16LE", str_enc)) { DEBUG(0, ("reg_parse_new: failed to set encoding: %s", str_enc)); goto fail; } assert(&s->reg_format_callback == (struct reg_format_callback*)s); return s; fail: talloc_free(s); return NULL; }
/*! Generate and log clicon error function call from Netconf error message * @param[in] xerr Netconf error message on the level: <rpc-reply><rpc-error> */ int clicon_rpc_generate_error(char *format, cxobj *xerr) { int retval = -1; cbuf *cb = NULL; cxobj *x; if ((cb = cbuf_new()) ==NULL){ clicon_err(OE_XML, errno, "cbuf_new"); goto done; } if ((x=xpath_first(xerr, "error-type"))!=NULL) cprintf(cb, "%s ", xml_body(x)); if ((x=xpath_first(xerr, "error-tag"))!=NULL) cprintf(cb, "%s ", xml_body(x)); if ((x=xpath_first(xerr, "error-message"))!=NULL) cprintf(cb, "%s ", xml_body(x)); if ((x=xpath_first(xerr, "error-info"))!=NULL) clicon_xml2cbuf(cb, xml_child_i(x,0), 0, 0); clicon_log(LOG_ERR, "%s: %s", format, cbuf_get(cb)); retval = 0; done: if (cb) cbuf_free(cb); return retval; }
void test_replace (void) { char str1[] = "\x01\x01\x01x\x01y\x01z\x01xy\x01yz\x01"; char *str2 = (char *)NULL; cbuffer_t *buf1 = (cbuffer_t *)NULL; cbuffer_t *buf2 = (cbuffer_t *)NULL; buf1 = cbuf_new (); cbuf_import (buf1, str1, strlen (str1)); buf2 = cbuf_replace (buf1, "\x01", ", ", 1, 2); if (buf2 != (cbuffer_t *)NULL) { str2 = (char *)xmalloc (buf2->sz + 1); if (str2 != (char *)NULL) { memset (str2, (int)NULL, buf2->sz + 1); memcpy (str2, buf2->data, buf2->sz); printf ("test_replace(): str1 = %s\n", str1); printf ("test_replace(): str2 = %s\n", str2); xfree (str2); } } cbuf_delete (buf1); cbuf_delete (buf2); }
/** * Parse option string * @param[in,out] ptr parse position * @param[in] mem_ctx talloc context * @param[out] name ptr 2 value * @param[out] value ptr 2 value * @return true on success */ bool srprs_option(const char** ptr, const void* mem_ctx, char** name, char** value) { const char* pos = *ptr; void* ctx = talloc_new(mem_ctx); cbuf* key = cbuf_new(ctx); cbuf* val = NULL; while(srprs_charsetinv(&pos, ",= \t\n\r", key)) ; if (pos == *ptr) { talloc_free(ctx); return false; } if (name != NULL) { *name = talloc_steal(mem_ctx, cbuf_gets(key, 0)); } if (*pos == '=') { val = cbuf_new(ctx); pos++; if (!srprs_quoted_string(ptr, val, NULL)) { while(srprs_charsetinv(&pos, ", \t\n\r", val)) ; } if (value != NULL) { *value = talloc_steal(mem_ctx, cbuf_gets(val, 0)); } } else { if (value != NULL) { *value = NULL; } } while(srprs_char(&pos, ',')) ; *ptr = pos; return true; }
/** * create a new component manager */ void *component_manager_new(void *ctx, void *subject) { component_manager_t *cm; cm = calloc(1, sizeof(component_manager_t)); cm->components = hashmap_new(__ulong_hash, __ulong_compare,11); cm->ctx = ctx; cm->subject = subject; // cm->event_queue = llqueue_new(); cm->event_queue = cbuf_new(16); return cm; }
void test_import (void) { char str1[] = "buffer one\n\x01\x02\nend buffer\n"; char str2[] = "buffer two\n\x01\x02\nend buffer\n"; char str3[] = "x" "\x01" "y" "\x01" "z" "\x01" "xy" "\x01" "yz"; cbuffer_t *buf1 = (cbuffer_t *)NULL; cbuffer_t *buf2 = (cbuffer_t *)NULL; cbuffer_t *buf3 = (cbuffer_t *)NULL; buf1 = cbuf_new (); buf2 = cbuf_new (); buf3 = cbuf_new (); cbuf_import (buf1, str1, strlen (str1)); cbuf_import (buf2, str2, strlen (str2)); cbuf_import (buf3, str3, strlen (str3)); cbuf_delete (buf1); cbuf_delete (buf2); cbuf_delete (buf3); }
void test_search (void) { char str1[] = "\x01\x01x234x\x01\x01y\x01\x01xy123\x01\x01"; deque_t *lst = (deque_t *)NULL; cbuffer_t *buf1 = (cbuffer_t *)NULL; buf1 = cbuf_new(); cbuf_import (buf1, str1, strlen (str1)); lst = cbuf_search (buf1, "\x01", 1); printf ("test_search(): len = %d\n", deque_length (lst)); deque_delete_nocb (lst); cbuf_delete (buf1); }
/*! Get database configuration * Same as clicon_proto_change just with a cvec instead of lvec * @param[in] h CLICON handle * @param[in] db Name of database * @param[in] xpath XPath (or "") * @param[out] xt XML tree. Free with xml_free. * Either <config> or <rpc-error>. * @retval 0 OK * @retval -1 Error, fatal or xml * @code * cxobj *xt = NULL; * if (clicon_rpc_get_config(h, "running", "/", &xt) < 0) * err; * if ((xerr = xpath_first(xt, "/rpc-error")) != NULL){ * clicon_rpc_generate_error("", xerr); * err; * } * if (xt) * xml_free(xt); * @endcode * @see clicon_rpc_generate_error */ int clicon_rpc_get_config(clicon_handle h, char *db, char *xpath, cxobj **xt) { int retval = -1; struct clicon_msg *msg = NULL; cbuf *cb = NULL; cxobj *xret = NULL; cxobj *xd; char *username; if ((cb = cbuf_new()) == NULL) goto done; cprintf(cb, "<rpc"); if ((username = clicon_username_get(h)) != NULL) cprintf(cb, " username=\"%s\"", username); cprintf(cb, "><get-config><source><%s/></source>", db); if (xpath && strlen(xpath)) cprintf(cb, "<filter type=\"xpath\" select=\"%s\"/>", xpath); cprintf(cb, "</get-config></rpc>"); if ((msg = clicon_msg_encode("%s", cbuf_get(cb))) == NULL) goto done; if (clicon_rpc_msg(h, msg, &xret, NULL) < 0) goto done; /* Send xml error back: first check error, then ok */ if ((xd = xpath_first(xret, "/rpc-reply/rpc-error")) != NULL) xd = xml_parent(xd); /* point to rpc-reply */ else if ((xd = xpath_first(xret, "/rpc-reply/data")) == NULL) if ((xd = xml_new("data", NULL, NULL)) == NULL) goto done; if (xt){ if (xml_rm(xd) < 0) goto done; *xt = xd; } retval = 0; done: if (cb) cbuf_free(cb); if (xret) xml_free(xret); if (msg) free(msg); return retval; }
void test_tail_head (void) { char str1[] = "123456"; char *str2 = (char *)NULL; char *str3 = (char *)NULL; cbuffer_t *buf1; cbuffer_t *buf2; cbuffer_t *buf3; buf1 = (cbuffer_t *)NULL; buf2 = (cbuffer_t *)NULL; buf3 = (cbuffer_t *)NULL; printf ("test_tail_head(): str1 = %s\n", (char *)str1); buf1 = cbuf_new(); cbuf_import (buf1, str1, strlen (str1)); buf2 = cbuf_head (buf1, 3); str2 = (char *)malloc (buf2->sz + 1); if (str2 != (char *)NULL) { memset (str2, (int)NULL, buf2->sz + 1); memcpy (str2, buf2->data, buf2->sz); printf ("test_tail_head(): str2 = %s\n", str2); free (str2); } buf3 = cbuf_tail (buf1, 3); str3 = (char *)malloc (buf3->sz + 1); if (str3 != (char *)NULL) { memset (str3, (int)NULL, buf3->sz + 1); memcpy (str3, buf3->data, buf3->sz); printf ("test_tail_head(): str3 = %s\n", str3); free (str3); } cbuf_delete (buf2); cbuf_delete (buf3); buf2 = cbuf_head_cut (buf1, 3); buf3 = cbuf_tail_cut (buf2, 3); cbuf_delete (buf2); cbuf_delete (buf3); cbuf_delete (buf1); }
connection *comm_connect(char *ipaddress, int connections) { int i, port; connection *conn; if (in_thread == NULL) start_threads(); if (connections < 1) return NULL; if (ipaddress == NULL) return NULL; conn = (connection *) malloc(sizeof(connection)); conn->label = strdup(ipaddress); conn->connected = 0; conn->sockets = (out_socket *) malloc(connections * sizeof(out_socket)); conn->num_sockets = connections; // setup the outgoing connections for (i = 0; i < connections; i++) { conn->sockets[i].fd = connect_to_socket(ipaddress, SOPHIA_PORT); set_non_blocking(conn->sockets[i].fd); pthread_mutex_init(&(conn->sockets[i].fd_lock), 0); conn->sockets[i].backlog = 0; conn->sockets[i].done = 0; } conn->connected = 1; // setup the rget connection conn->rget_settings.buffer = cbuf_new(); conn->rget_settings.client_fd = -1; conn->rget_settings.server_fd = -1; while( conn->rget_settings.server_fd < 0 ) { port = randomise_port(); conn->rget_settings.server_fd = listen_on_socket(port); } // comm_send(conn, 1, "void", 1, NULL, NULL, "[RGetRegisterClient \"%d\" \"%s\"]", port, "10.0.0.12"); // REMOTE get_local_ip()); comm_send(conn, 1, "void", 1, NULL, NULL, "[RGetRegisterClient \"%d\" \"%s\"]", port, get_local_ip(conn->sockets[0].fd)); // wait to accept the rget connection while (conn->rget_settings.client_fd < 0) { conn->rget_settings.client_fd = accept(conn->rget_settings.server_fd, NULL, 0); } // add this connect to the inbound subsystem comm_in_add(&(conn->rget_settings)); return conn; }
/*! Send database entries as XML to backend daemon * @param[in] h CLICON handle * @param[in] db Name of database * @param[in] op Operation on database item: OP_MERGE, OP_REPLACE * @param[in] xml XML string. Ex: <config><a>..</a><b>...</b></config> * @retval 0 OK * @retval -1 Error and logged to syslog * @note xml arg need to have <config> as top element * @code * if (clicon_rpc_edit_config(h, "running", OP_MERGE, * "<config><a>4</a></config>") < 0) * err; * @endcode */ int clicon_rpc_edit_config(clicon_handle h, char *db, enum operation_type op, char *xmlstr) { int retval = -1; struct clicon_msg *msg = NULL; cbuf *cb = NULL; cxobj *xret = NULL; cxobj *xerr; char *username; if ((cb = cbuf_new()) == NULL) goto done; cprintf(cb, "<rpc %s", DEFAULT_XMLNS); if ((username = clicon_username_get(h)) != NULL) cprintf(cb, " username=\"%s\"", username); cprintf(cb, "><edit-config><target><%s/></target>", db); cprintf(cb, "<default-operation>%s</default-operation>", xml_operation2str(op)); if (xmlstr) cprintf(cb, "%s", xmlstr); cprintf(cb, "</edit-config></rpc>"); if ((msg = clicon_msg_encode("%s", cbuf_get(cb))) == NULL) goto done; if (clicon_rpc_msg(h, msg, &xret, NULL) < 0) goto done; if ((xerr = xpath_first(xret, "//rpc-error")) != NULL){ clicon_rpc_generate_error("Editing configuration", xerr); goto done; } retval = 0; done: if (xret) xml_free(xret); if (cb) cbuf_free(cb); if (msg) free(msg); return retval; }
/*! Reset running and start in failsafe mode. If no failsafe then quit. Typically done when startup status is not OK so failsafe ----------------------+ reset \ commit running |-------+---------------> RUNNING FAILSAFE */ int startup_failsafe(clicon_handle h) { int retval = -1; int ret; char *db = "failsafe"; cbuf *cbret = NULL; if ((cbret = cbuf_new()) == NULL){ clicon_err(OE_XML, errno, "cbuf_new"); goto done; } if ((ret = xmldb_exists(h, db)) < 0) goto done; if (ret == 0){ /* No it does not exist, fail */ clicon_err(OE_DB, 0, "Startup failed and no Failsafe database found, exiting"); goto done; } /* Copy original running to tmp as backup (restore if error) */ if (xmldb_copy(h, "running", "tmp") < 0) goto done; if (startup_db_reset(h, "running") < 0) goto done; ret = candidate_commit(h, db, cbret); if (ret != 1) if (xmldb_copy(h, "tmp", "running") < 0) goto done; if (ret < 0) goto done; if (ret == 0){ clicon_err(OE_DB, 0, "Startup failed, Failsafe database validation failed %s", cbuf_get(cbret)); goto done; } clicon_log(LOG_NOTICE, "Startup failed, Failsafe database loaded "); retval = 0; done: if (cbret) cbuf_free(cbret); return retval; }
/*! 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; }
void test_new (void) { cbuffer_t *buf = cbuf_new (); cbuf_delete (buf); }
/*! 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; }
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; }
/*! 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; }
/*! 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; }