From 6169ea6bed10e5911c2ad8016603716479597628 Mon Sep 17 00:00:00 2001 From: Olof hagsand Date: Mon, 14 Mar 2016 21:22:37 +0100 Subject: [PATCH] incremental debuggung --- apps/backend/backend_client.c | 42 +++++++++++++++++++++++ apps/backend/backend_main.c | 8 ++--- apps/cli/cli_common.c | 27 ++++----------- apps/dbctrl/dbctrl_main.c | 2 +- apps/netconf/netconf_rpc.c | 8 +++-- example/README | 2 ++ example/routing.conf.local | 7 ---- lib/clixon/clixon_proto.h | 4 +++ lib/clixon/clixon_proto_client.h | 1 + lib/clixon/clixon_proto_encode.h | 9 +++++ lib/clixon/clixon_xml_db.h | 2 +- lib/src/clixon_file.c | 6 ++-- lib/src/clixon_proto_client.c | 27 +++++++++++++++ lib/src/clixon_proto_encode.c | 58 ++++++++++++++++++++++++++++++++ lib/src/clixon_qdb.c | 8 +++++ lib/src/clixon_xml_db.c | 52 ++++++++++++++++------------ lib/src/clixon_yang.c | 4 +-- 17 files changed, 203 insertions(+), 64 deletions(-) diff --git a/apps/backend/backend_client.c b/apps/backend/backend_client.c index 6033ca46..400f6ead 100644 --- a/apps/backend/backend_client.c +++ b/apps/backend/backend_client.c @@ -502,6 +502,44 @@ from_client_load(clicon_handle h, return retval; } +/*! Internal message: Copy file from file1 to file2 + * @param[in] h Clicon handle + * @param[in] s Socket where request arrived, and where replies are sent + * @param[in] pid Unix process id + * @param[in] msg Message + * @param[in] label Memory chunk + * @retval 0 OK + * @retval -1 Error. Send error message back to client. + */ +static int +from_client_copy(clicon_handle h, + int s, + int pid, + struct clicon_msg *msg, + const char *label) +{ + char *db1; + char *db2; + int retval = -1; + + if (clicon_msg_copy_decode(msg, + &db1, + &db2, + label) < 0){ + send_msg_err(s, clicon_errno, clicon_suberrno, + clicon_err_reason); + goto done; + } + if (xmldb_copy(h, db1, db2) < 0) + goto done; + if (send_msg_ok(s) < 0) + goto done; + retval = 0; + done: + return retval; +} + + /*! Internal message: Kill session (Kill the process) * @param[in] h Clicon handle * @param[in] s Client socket where request arrived, and where replies are sent @@ -736,6 +774,10 @@ from_client(int s, void* arg) if (from_client_load(h, ce->ce_s, ce->ce_pid, msg, __FUNCTION__) < 0) goto done; break; + case CLICON_MSG_COPY: + if (from_client_copy(h, ce->ce_s, ce->ce_pid, msg, __FUNCTION__) < 0) + goto done; + break; case CLICON_MSG_KILL: if (from_client_kill(h, ce->ce_s, msg, __FUNCTION__) < 0) goto done; diff --git a/apps/backend/backend_main.c b/apps/backend/backend_main.c index a4d74bed..c800bcfe 100644 --- a/apps/backend/backend_main.c +++ b/apps/backend/backend_main.c @@ -542,13 +542,11 @@ main(int argc, char **argv) if (rundb_main(h, app_config_file) < 0) goto done; - /* Initiate the shared candidate. Maybe we should not do this? */ + /* Initiate the shared candidate. Maybe we should not do this? + * Too strict access + */ if (xmldb_copy(h, "running", "candidate") < 0) goto done; -#ifdef OBSOLETE - /* XXX Hack for now. Change mode so that we all can write. Security issue*/ - chmod(candidate_db, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH); -#endif if (once) goto done; diff --git a/apps/cli/cli_common.c b/apps/cli/cli_common.c index 2a5c221b..f07b4049 100644 --- a/apps/cli/cli_common.c +++ b/apps/cli/cli_common.c @@ -78,7 +78,7 @@ init_candidate_db(clicon_handle h) goto err; } if (xmldb_exists(h, "candidate") != 1) - if (xmldb_copy(h, "running", "candidate") < 0) + if (clicon_rpc_copy(h, "running", "candidate") < 0) goto err; retval = 0; err: @@ -648,7 +648,7 @@ compare_dbs(clicon_handle h, cvec *cvv, cg_var *arg) } -/*! Modify xml database frm a callback using xml key format strings +/*! Modify xml database 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] arg An xml key format string, eg /aaa/%s @@ -676,18 +676,6 @@ cli_dbxml(clicon_handle h, cg_var *cval; char *val = NULL; - /* - * clicon_rpc_xmlput(h, db, MERGE,"eth0hej"); - * Wanted database content: - * /interfaces - * /interfaces/interface/eth0 - * /interfaces/interface/eth0/name eth0 - * /interfaces/interface/eth0/type hej - * Algorithm alt1: - * arg = "$1$2" - * Where is arg computed? In eg yang2cli_leaf, otherwise in yang_parse,.. - * Create string using cbuf and save that. - */ xkfmt = cv_string_get(arg); if (xmlkeyfmt2key(xkfmt, cvv, &xk) < 0) goto done; @@ -944,22 +932,21 @@ delete_all(clicon_handle h, cvec *cvv, cg_var *arg) clicon_err(OE_PLUGIN, 0, "No such db name: %s", dbstr); goto done; } - if (xmldb_delete(h, dbstr) < 0) - goto done; - if (xmldb_init(h, dbstr) < 0) - goto done; + if (clicon_rpc_change(h, "candidate", + OP_REMOVE, + "/", "") < 0) + goto done; retval = 0; done: return retval; } /*! Discard all changes in candidate and replace with running - * Utility function used by cligen spec file */ int discard_changes(clicon_handle h, cvec *cvv, cg_var *arg) { - return xmldb_copy(h, "running", "candidate"); + return clicon_rpc_copy(h, "running", "candidate"); } /*! Generic function for showing configurations. diff --git a/apps/dbctrl/dbctrl_main.c b/apps/dbctrl/dbctrl_main.c index e9126f67..c73e21ba 100644 --- a/apps/dbctrl/dbctrl_main.c +++ b/apps/dbctrl/dbctrl_main.c @@ -196,7 +196,7 @@ main(int argc, char **argv) } if (dumpdb){ /* Here db must be local file-path */ - if (xmldb_dump(stdout, db, matchkey)) { + if (xmldb_dump_local(stdout, db, matchkey)) { fprintf(stderr, "Match error\n"); goto done; } diff --git a/apps/netconf/netconf_rpc.c b/apps/netconf/netconf_rpc.c index eaadaab8..e33c2e67 100644 --- a/apps/netconf/netconf_rpc.c +++ b/apps/netconf/netconf_rpc.c @@ -505,7 +505,7 @@ netconf_copy_config(clicon_handle h, goto done; } #endif - if (xmldb_copy(h, source, target) < 0){ + if (clicon_rpc_copy(h, source, target) < 0){ netconf_create_rpc_error(cb_err, xorig, "operation-failed", "protocol", "error", @@ -556,7 +556,9 @@ netconf_delete_config(clicon_handle h, "target"); goto done; } - if (xmldb_delete(h, target) < 0){ + if (clicon_rpc_change(h, "candidate", + OP_REMOVE, + "/", "") < 0){ netconf_create_rpc_error(cb_err, xorig, "operation-failed", "protocol", "error", @@ -750,7 +752,7 @@ netconf_discard_changes(clicon_handle h, { int retval = -1; - if (xmldb_copy(h, "running", "candidate") < 0){ + if (clicon_rpc_copy(h, "running", "candidate") < 0){ netconf_create_rpc_error(cb_err, xorig, "operation-failed", "protocol", "error", diff --git a/example/README b/example/README index 79e23298..4c7c37cc 100644 --- a/example/README +++ b/example/README @@ -32,6 +32,8 @@ Clixon yang routing example ]]>]]> +]]>]]> + 3. Run as docker container -------------------------- cd docker diff --git a/example/routing.conf.local b/example/routing.conf.local index 6b950c66..b22b2b5f 100644 --- a/example/routing.conf.local +++ b/example/routing.conf.local @@ -1,21 +1,14 @@ # Main YANG module first parsed by parser (in CLICON_YANG_DIR). eg clicon.yang. -# Save values as XML in database instead of lvec:s. -# This is optimized for yang specified applications -# But not compatible with key-based application (eg Rost) -CLICON_DB_XML 1 - # Startup CLI mode. This should match the CLICON_MODE in your startup clispec file CLICON_CLI_MODE routing # Option used to construct initial yang file: # [@] -# This option is only relevant if CLICON_DBSPEC_TYPE is YANG CLICON_YANG_MODULE_MAIN ietf-ip # Option used to construct initial yang file: # [@] -# This option is only relevant if CLICON_DBSPEC_TYPE is YANG CLICON_YANG_MODULE_REVISION 2014-06-16 # Generate code for CLI completion of existing db symbols diff --git a/lib/clixon/clixon_proto.h b/lib/clixon/clixon_proto.h index af7ef511..1c624d63 100644 --- a/lib/clixon/clixon_proto.h +++ b/lib/clixon/clixon_proto.h @@ -71,6 +71,10 @@ enum clicon_msg_type{ 3. string: filename to load from */ + CLICON_MSG_COPY, /* Copy from file to file in backend. Body is: + 1. string: filename to copy from + 2. string: filename to copy to + */ CLICON_MSG_KILL, /* Kill (other) session: 1. session-id */ diff --git a/lib/clixon/clixon_proto_client.h b/lib/clixon/clixon_proto_client.h index 3f9e6cce..0665bb9e 100644 --- a/lib/clixon/clixon_proto_client.h +++ b/lib/clixon/clixon_proto_client.h @@ -39,6 +39,7 @@ int clicon_rpc_dbitems(clicon_handle h, char *db, char *rx, cvec ***cvv, size_t *cvvlen); int clicon_rpc_save(clicon_handle h, char *dbname, int snapshot, char *filename); int clicon_rpc_load(clicon_handle h, int replace, char *db, char *filename); +int clicon_rpc_copy(clicon_handle h, char *db1, char *db2); int clicon_rpc_kill(clicon_handle h, int session_id); int clicon_rpc_debug(clicon_handle h, int level); int clicon_rpc_call(clicon_handle h, uint16_t op, char *plugin, char *func, diff --git a/lib/clixon/clixon_proto_encode.h b/lib/clixon/clixon_proto_encode.h index 575eee59..5c7332a5 100644 --- a/lib/clixon/clixon_proto_encode.h +++ b/lib/clixon/clixon_proto_encode.h @@ -101,6 +101,15 @@ clicon_msg_load_decode(struct clicon_msg *msg, int *replace, char **db, char **filename, const char *label); +struct clicon_msg * +clicon_msg_copy_encode(char *db_src, char *db_dst, + const char *label); + +int +clicon_msg_copy_decode(struct clicon_msg *msg, + char **db_src, char **db_dst, + const char *label); + struct clicon_msg * clicon_msg_kill_encode(uint32_t session_id, const char *label); diff --git a/lib/clixon/clixon_xml_db.h b/lib/clixon/clixon_xml_db.h index e2eb9f51..c3e11e0c 100644 --- a/lib/clixon/clixon_xml_db.h +++ b/lib/clixon/clixon_xml_db.h @@ -35,7 +35,7 @@ int xmldb_put(clicon_handle h, char *db, cxobj *xt, enum operation_type op); int xmldb_put_xkey(clicon_handle h, char *db, char *xkey, char *val, enum operation_type op); -int xmldb_dump(FILE *f, char *dbfilename, char *rxkey); +int xmldb_dump_local(FILE *f, char *dbfilename, char *rxkey); int xmldb_copy(clicon_handle h, char *from, char *to); int xmldb_lock(clicon_handle h, char *db, int pid); int xmldb_unlock(clicon_handle h, char *db, int pid); diff --git a/lib/src/clixon_file.c b/lib/src/clixon_file.c index e5afb6dc..260e5c85 100644 --- a/lib/src/clixon_file.c +++ b/lib/src/clixon_file.c @@ -307,17 +307,17 @@ clicon_file_copy(char *src, return -1; } if((inF = open(src, O_RDONLY)) == -1) { - clicon_err(OE_UNIX, errno, "open"); + clicon_err(OE_UNIX, errno, "open(%s) for read", src); return -1; } if((ouF = open(target, O_WRONLY | O_CREAT | O_TRUNC, st.st_mode)) == -1) { - clicon_err(OE_UNIX, errno, "open"); + clicon_err(OE_UNIX, errno, "open(%s) for write", target); err = errno; goto error; } while((bytes = read(inF, line, sizeof(line))) > 0) if (write(ouF, line, bytes) < 0){ - clicon_err(OE_UNIX, errno, "write"); + clicon_err(OE_UNIX, errno, "write(%s)", src); err = errno; goto error; } diff --git a/lib/src/clixon_proto_client.c b/lib/src/clixon_proto_client.c index 251188e5..be85453f 100644 --- a/lib/src/clixon_proto_client.c +++ b/lib/src/clixon_proto_client.c @@ -171,6 +171,7 @@ clicon_rpc_validate(clicon_handle h, * @param[in] value value as string * @retval 0 OK * @retval -1 Error + * @note special case: remove all: key:"/" op:OP_REMOVE */ int clicon_rpc_change(clicon_handle h, @@ -284,6 +285,32 @@ clicon_rpc_load(clicon_handle h, return retval; } +/*! Send a request to backend to copy a file from one location to another + * Note this assumes the backend can access these files and (usually) assumes + * clients and servers have the access to the same filesystem. + * @param[in] h CLICON handle + * @param[in] db1 src database, eg "candidate" + * @param[in] db2 dst database, eg "running" + */ +int +clicon_rpc_copy(clicon_handle h, + char *db1, + char *db2) +{ + int retval = -1; + struct clicon_msg *msg; + + if ((msg=clicon_msg_copy_encode(db1, db2, __FUNCTION__)) == NULL) + goto done; + if (clicon_rpc_msg(h, msg, NULL, NULL, NULL, __FUNCTION__) < 0) + goto done; + retval = 0; + done: + unchunk_group(__FUNCTION__); + return retval; +} + + /*! Send a kill session request to backend server * @param[in] h CLICON handle * @param[in] session_id Id of session to kill diff --git a/lib/src/clixon_proto_encode.c b/lib/src/clixon_proto_encode.c index cc4ff8bb..2f35b6ad 100644 --- a/lib/src/clixon_proto_encode.c +++ b/lib/src/clixon_proto_encode.c @@ -498,6 +498,64 @@ clicon_msg_load_decode(struct clicon_msg *msg, return 0; } +struct clicon_msg * +clicon_msg_copy_encode(char *db_src, char *db_dst, + const char *label) +{ + struct clicon_msg *msg; + int hdrlen = sizeof(*msg); + uint16_t len; + int p; + + clicon_debug(2, "%s: db_src: %s db_dst: %s", + __FUNCTION__, + db_src, db_dst); + p = 0; + len = hdrlen + strlen(db_src) + 1 + strlen(db_dst) + 1; + if ((msg = (struct clicon_msg *)chunk(len, label)) == NULL){ + clicon_err(OE_PROTO, errno, "%s: chunk", __FUNCTION__); + return NULL; + } + memset(msg, 0, len); + /* hdr */ + msg->op_type = htons(CLICON_MSG_COPY); + msg->op_len = htons(len); + /* body */ + strncpy(msg->op_body+p, db_src, len-p-hdrlen); + p += strlen(db_src)+1; + strncpy(msg->op_body+p, db_dst, len-p-hdrlen); + p += strlen(db_dst)+1; + return msg; +} + +int +clicon_msg_copy_decode(struct clicon_msg *msg, + char **db_src, char **db_dst, + const char *label) +{ + int p; + + p = 0; + /* body */ + if ((*db_src = chunk_sprintf(label, "%s", msg->op_body+p)) == NULL){ + clicon_err(OE_PROTO, errno, "%s: chunk_sprintf", + __FUNCTION__); + return -1; + } + p += strlen(*db_src)+1; + + if ((*db_dst = chunk_sprintf(label, "%s", msg->op_body+p)) == NULL){ + clicon_err(OE_PROTO, errno, "%s: chunk_sprintf", + __FUNCTION__); + return -1; + } + p += strlen(*db_dst)+1; + clicon_debug(2, "%s: db_src: %s db_dst: %s", + __FUNCTION__, + *db_src, *db_dst); + return 0; +} + struct clicon_msg * clicon_msg_kill_encode(uint32_t session_id, const char *label) { diff --git a/lib/src/clixon_qdb.c b/lib/src/clixon_qdb.c index 4033a460..93b5a09b 100644 --- a/lib/src/clixon_qdb.c +++ b/lib/src/clixon_qdb.c @@ -105,9 +105,17 @@ db_init(char *file) return db_init_mode(file, DP_OWRITER | DP_OCREAT ); /* DP_OTRUNC? */ } +/*! Remove database by removing file, if it exists * + * @param[in] file database file + */ int db_delete(char *file) { + struct stat sb; + + if (stat(file, &sb) < 0){ + return 0; + } if (unlink(file) < 0){ clicon_err(OE_DB, errno, "unlink %s", file); return -1; diff --git a/lib/src/clixon_xml_db.c b/lib/src/clixon_xml_db.c index bc2e5a86..0ee6ccb4 100644 --- a/lib/src/clixon_xml_db.c +++ b/lib/src/clixon_xml_db.c @@ -594,22 +594,20 @@ get(char *dbname, clicon_err(OE_XML, 0, "Malformed key: %s", xk); goto done; } - name = vec[1]; - if ((y = yang_find_topnode(ys, name)) == NULL){ - clicon_err(OE_UNIX, errno, "No yang node found: %s", name); - goto done; - } - if ((xc = xml_find(x, name))==NULL) - if ((xc = xml_new_spec(name, x, y)) == NULL) - goto done; - x = xc; - i = 2; + i = 1; while (imodule->node */ + if ((y = yang_find_topnode(ys, name)) == NULL){ + clicon_err(OE_UNIX, errno, "No yang node found: %s", name); + goto done; + } } + else + if ((y = yang_find_syntax((yang_node*)y, name)) == NULL){ + clicon_err(OE_UNIX, errno, "No yang node found: %s", name); + goto done; + } switch (y->ys_keyword){ case Y_LEAF_LIST: /* @@ -664,7 +662,9 @@ get(char *dbname, x = xc; } /* while */ break; - default: + case Y_LEAF: + case Y_CONTAINER: + default: if ((xc = xml_find(x, name))==NULL) if ((xc = xml_new_spec(name, x, y)) == NULL) goto done; @@ -1158,7 +1158,6 @@ xmldb_put_local(clicon_handle h, return retval; } - /*! Modify database provided an xml tree and an operation * @param[in] dbname Name of database to search in (filename including dir path) * @param[in] h CLICON handle @@ -1239,8 +1238,14 @@ xmldb_put_xkey_local(clicon_handle h, while (i=nvec){ + if (i>nvec){ /* XXX >= ? */ clicon_err(OE_XML, errno, "List %s without argument", name); goto done; } @@ -1291,8 +1296,8 @@ xmldb_put_xkey_local(clicon_handle h, if (op == OP_MERGE || op == OP_REPLACE || op == OP_CREATE) if (db_set(filename, cbuf_get(csubkey), val2, strlen(val2)+1) < 0) goto done; - break; } + break; default: if (op == OP_MERGE || op == OP_REPLACE || op == OP_CREATE) if (db_set(filename, cbuf_get(ckey), NULL, 0) < 0) @@ -1390,9 +1395,9 @@ xmldb_put_xkey(clicon_handle h, * @note This function can only be called locally. */ int -xmldb_dump(FILE *f, - char *dbfilename, - char *rxkey) +xmldb_dump_local(FILE *f, + char *dbfilename, + char *rxkey) { int retval = -1; int npairs; @@ -1415,6 +1420,7 @@ xmldb_dump(FILE *f, return retval; } + /*! Local variant of xmldb_copy */ static int xmldb_copy_local(clicon_handle h, @@ -1619,7 +1625,9 @@ xmldb_delete_local(clicon_handle h, return retval; } -/*! Delete database. Remove file */ +/*! Delete database. Remove file + * Should not be called from client. Use change("/", OP_REMOVE) instead. + */ int xmldb_delete(clicon_handle h, char *db) diff --git a/lib/src/clixon_yang.c b/lib/src/clixon_yang.c index 4e9cfbb3..8ebea297 100644 --- a/lib/src/clixon_yang.c +++ b/lib/src/clixon_yang.c @@ -448,9 +448,9 @@ yang_find_syntax(yang_node *yn, char *argument) return ysmatch; } -/*! Help function to check find 'top-node', eg first 'syntax node in a spec +/*! Help function to check find 'top-node', eg first 'syntax' node in a spec * A yang specification has modules as children which in turn can have - * syntax-nodes as children. This function goes through all the modulers to + * syntax-nodes as children. This function goes through all the modules to * look for syntax-nodes. Note that if a child to a module is a choice, * the search is made recursively made to the choice's children. */