diff --git a/apps/Makefile.in b/apps/Makefile.in index 65631f6b..cb3093fc 100644 --- a/apps/Makefile.in +++ b/apps/Makefile.in @@ -27,7 +27,7 @@ LIBS = @LIBS@ SHELL = /bin/sh -SUBDIRS = cli backend dbctrl netconf +SUBDIRS = cli backend dbctrl netconf xmldb .PHONY: all clean depend install $(SUBDIRS) diff --git a/apps/backend/Makefile.in b/apps/backend/Makefile.in index f31ec42f..d03f56bb 100644 --- a/apps/backend/Makefile.in +++ b/apps/backend/Makefile.in @@ -54,7 +54,7 @@ INCLUDES = -I. -I$(top_srcdir)/lib/src -I$(top_srcdir)/lib -I$(top_srcdir)/inclu # Not accessible from plugin APPSRC = backend_main.c backend_socket.c backend_client.c \ - backend_lock.c backend_commit.c backend_plugin.c + backend_commit.c backend_plugin.c APPOBJ = $(APPSRC:.c=.o) APPL = clixon_backend diff --git a/apps/backend/backend_client.c b/apps/backend/backend_client.c index 6baa7706..6033ca46 100644 --- a/apps/backend/backend_client.c +++ b/apps/backend/backend_client.c @@ -51,7 +51,6 @@ #include #include "backend_commit.h" -#include "backend_lock.h" #include "backend_plugin.h" #include "backend_client.h" #include "backend_handle.h" @@ -163,7 +162,6 @@ backend_client_rm(clicon_handle h, return backend_client_delete(h, ce); /* actually purge it */ } - /*! Internal message: Change entry set/delete in database xmldb variant * @param[in] h Clicon handle * @param[in] s Socket where request arrived, and where replies are sent @@ -183,15 +181,14 @@ from_client_change(clicon_handle h, int retval = -1; uint32_t len; char *xk; - char *dbname; + char *db; enum operation_type op; char *str = NULL; - char *candidate_db; char *val=NULL; - yang_spec *yspec; + int piddb; if (clicon_msg_change_decode(msg, - &dbname, + &db, &op, &xk, &val, @@ -201,25 +198,17 @@ from_client_change(clicon_handle h, clicon_err_reason); goto done; } - if ((candidate_db = clicon_candidate_db(h)) == NULL){ - send_msg_err(s, 0, 0, "candidate db not set"); - goto done; - } /* candidate is locked by other client */ - if (strcmp(dbname, candidate_db) == 0 && - db_islocked(h) && - pid != db_islocked(h)){ - send_msg_err(s, OE_DB, 0, - "lock failed: locked by %d", db_islocked(h)); - goto done; + if (strcmp(db, "candidate") == 0){ + piddb = xmldb_islocked(h, db); + if (piddb && pid != piddb){ + send_msg_err(s, OE_DB, 0, + "lock failed: locked by %d", piddb); + goto done; + } } - /* Update database */ - if ((yspec = clicon_dbspec_yang(h)) == NULL){ - clicon_err(OE_XML, 0, "yang spec not found"); - goto done; - } - if (xmldb_put_xkey(dbname, xk, val, yspec, op) < 0){ + if (xmldb_put_xkey(h, db, xk, val, op) < 0){ send_msg_err(s, clicon_errno, clicon_suberrno, clicon_err_reason); goto done; @@ -233,8 +222,6 @@ from_client_change(clicon_handle h, return retval; } - - /*! Internal message: Change entries as XML * @param[in] h Clicon handle * @param[in] s Socket where request arrived, and where replies are sent @@ -252,19 +239,16 @@ from_client_xmlput(clicon_handle h, const char *label) { int retval = -1; - char *dbname; + char *db; enum operation_type op; cvec *cvv = NULL; char *str = NULL; char *xml = NULL; - yang_spec *ys; - char *candidate_db; cxobj *xt; + int piddb; - if ((ys = clicon_dbspec_yang(h)) == NULL) - goto done; if (clicon_msg_xmlput_decode(msg, - &dbname, + &db, &op, &xml, label) < 0){ @@ -272,24 +256,21 @@ from_client_xmlput(clicon_handle h, clicon_err_reason); goto done; } - if ((candidate_db = clicon_candidate_db(h)) == NULL){ - send_msg_err(s, 0, 0, "candidate db not set"); - goto done; - } /* candidate is locked by other client */ - if (strcmp(dbname, candidate_db) == 0 && - db_islocked(h) && - pid != db_islocked(h)){ - send_msg_err(s, OE_DB, 0, - "lock failed: locked by %d", db_islocked(h)); - goto done; + if (strcmp(db, "candidate") == 0){ + piddb = xmldb_islocked(h, db); + if (piddb && pid != piddb){ + send_msg_err(s, OE_DB, 0, + "lock failed: locked by %d", piddb); + goto done; + } } if (clicon_xml_parse_string(&xml, &xt) < 0){ send_msg_err(s, clicon_errno, clicon_suberrno, clicon_err_reason); goto done; } - if (xmldb_put(dbname, xt, ys, op) < 0){ + if (xmldb_put(h, db, xt, op) < 0){ send_msg_err(s, clicon_errno, clicon_suberrno, clicon_err_reason); goto done; @@ -312,7 +293,7 @@ from_client_xmlput(clicon_handle h, */ int config_snapshot(clicon_handle h, - char *dbname, + char *db, char *dir) { int retval = -1; @@ -322,7 +303,6 @@ config_snapshot(clicon_handle h, int i; FILE *f = NULL; cxobj *xn; - yang_spec *yspec = clicon_dbspec_yang(h); if (stat(dir, &st) < 0){ clicon_err(OE_CFG, errno, "%s: stat(%s): %s\n", @@ -354,7 +334,7 @@ config_snapshot(clicon_handle h, clicon_err(OE_CFG, errno, "Creating file %s", filename0); return -1; } - if (xmldb_get(dbname, "/", yspec, &xn) < 0) + if (xmldb_get(h, db, "/", 0, &xn, NULL, NULL) < 0) goto done; if (clicon_xml2file(f, xn, 0, 1) < 0) goto done; @@ -389,7 +369,6 @@ from_client_save(clicon_handle h, uint32_t snapshot; FILE *f = NULL; cxobj *xn = NULL; - yang_spec *yspec; if (clicon_msg_save_decode(msg, &db, @@ -400,6 +379,10 @@ from_client_save(clicon_handle h, clicon_err_reason); goto done; } + if (strcmp(db, "running") != 0 && strcmp(db, "candidate") != 0){ + clicon_err(OE_XML, 0, "Expected running or candidate, got %s", db); + goto done; + } if (snapshot){ if ((archive_dir = clicon_archive_dir(h)) == NULL){ clicon_err(OE_PLUGIN, 0, "snapshot set and clicon_archive_dir not defined"); @@ -417,8 +400,7 @@ from_client_save(clicon_handle h, clicon_err(OE_CFG, errno, "Creating file %s", filename); return -1; } - yspec = clicon_dbspec_yang(h); - if (xmldb_get(db, "/", yspec, &xn) < 0) + if (xmldb_get(h, db, "/", 0, &xn, NULL, NULL) < 0) goto done; if (clicon_xml2file(f, xn, 0, 1) < 0) goto done; @@ -453,40 +435,41 @@ from_client_load(clicon_handle h, { char *filename = NULL; int retval = -1; - char *dbname = NULL; + char *db = NULL; int replace = 0; - char *candidate_db; int fd = -1; cxobj *xt = NULL; cxobj *xn; - yang_spec *yspec; + int piddb; if (clicon_msg_load_decode(msg, &replace, - &dbname, + &db, &filename, label) < 0){ send_msg_err(s, clicon_errno, clicon_suberrno, clicon_err_reason); goto done; } - if ((candidate_db = clicon_candidate_db(h)) == NULL){ - send_msg_err(s, 0, 0, "candidate db not set"); + if (strcmp(db, "running") != 0 && strcmp(db, "candidate") != 0){ + clicon_err(OE_XML, 0, "Expected running or candidate, got %s", db); goto done; } /* candidate is locked by other client */ - if (strcmp(dbname, candidate_db) == 0 && - db_islocked(h) && - pid != db_islocked(h)){ - send_msg_err(s, OE_DB, 0, "lock failed: locked by %d", db_islocked(h)); - goto done; + if (strcmp(db, "candidate") == 0){ + piddb = xmldb_islocked(h, db); + if (piddb && pid != piddb){ + send_msg_err(s, OE_DB, 0, + "lock failed: locked by %d", piddb); + goto done; + } } if (replace){ - if (unlink(dbname) < 0){ + if (xmldb_delete(h, db) < 0){ send_msg_err(s, OE_UNIX, 0, "rm %s %s", filename, strerror(errno)); goto done; } - if (xmldb_init(dbname) < 0) + if (xmldb_init(h, db) < 0) goto done; } @@ -501,9 +484,8 @@ from_client_load(clicon_handle h, clicon_err_reason); goto done; } - yspec = clicon_dbspec_yang(h); if ((xn = xml_child_i(xt, 0)) != NULL){ - if (xmldb_put(dbname, xn, yspec, replace?OP_REPLACE:OP_MERGE) < 0){ + if (xmldb_put(h, db, xn, replace?OP_REPLACE:OP_MERGE) < 0){ send_msg_err(s, clicon_errno, clicon_suberrno, clicon_err_reason); goto done; @@ -520,270 +502,6 @@ from_client_load(clicon_handle h, return retval; } -/*! Internal message: Initialize database - * @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_initdb(clicon_handle h, - int s, - int pid, - struct clicon_msg *msg, - const char *label) -{ - char *filename1; - int retval = -1; - char *candidate_db; - - if (clicon_msg_initdb_decode(msg, - &filename1, - label) < 0){ - send_msg_err(s, clicon_errno, clicon_suberrno, - clicon_err_reason); - goto done; - } - if ((candidate_db = clicon_candidate_db(h)) == NULL){ - send_msg_err(s, 0, 0, "candidate db not set"); - goto done; - } - /* candidate is locked by other client */ - if (strcmp(filename1, candidate_db) == 0 && - db_islocked(h) && - pid != db_islocked(h)){ - send_msg_err(s, OE_DB, 0, "lock failed: locked by %d", db_islocked(h)); - goto done; - } - - if (xmldb_init(filename1) < 0) - goto done; - /* Change mode if shared candidate. XXXX full rights for all is no good */ - if (strcmp(filename1, candidate_db) == 0) - chmod(filename1, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH); - - if (send_msg_ok(s) < 0) - goto done; - retval = 0; - done: - return retval; -} - -/*! Internal message: Remove file - * @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_rm(clicon_handle h, - int s, - int pid, - struct clicon_msg *msg, - const char *label) -{ - char *filename1; - int retval = -1; - char *candidate_db; - - if (clicon_msg_rm_decode(msg, - &filename1, - label) < 0){ - send_msg_err(s, clicon_errno, clicon_suberrno, - clicon_err_reason); - goto done; - } - if ((candidate_db = clicon_candidate_db(h)) == NULL){ - send_msg_err(s, 0, 0, "candidate db not set"); - goto done; - } - /* candidate is locked by other client */ - if (strcmp(filename1, candidate_db) == 0 && - db_islocked(h) && - pid != db_islocked(h)){ - send_msg_err(s, OE_DB, 0, "lock failed: locked by %d", db_islocked(h)); - goto done; - } - - if (unlink(filename1) < 0){ - send_msg_err(s, OE_UNIX, 0, "rm %s %s", filename1, strerror(errno)); - goto done; - } - if (send_msg_ok(s) < 0) - goto done; - retval = 0; - done: - 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 *filename1; - char *filename2; - int retval = -1; - char *candidate_db; - - if (clicon_msg_copy_decode(msg, - &filename1, - &filename2, - label) < 0){ - send_msg_err(s, clicon_errno, clicon_suberrno, - clicon_err_reason); - goto done; - } - if ((candidate_db = clicon_candidate_db(h)) == NULL){ - send_msg_err(s, 0, 0, "candidate db not set"); - goto done; - } - - /* candidate is locked by other client */ - if (strcmp(filename2, candidate_db) == 0 && - db_islocked(h) && - pid != db_islocked(h)){ - send_msg_err(s, OE_DB, 0, "lock failed: locked by %d", db_islocked(h)); - goto done; - } - - if (file_cp(filename1, filename2) < 0){ - send_msg_err(s, OE_UNIX, errno, "copy %s to %s", filename1, filename2); - goto done; - } - /* Change mode if shared candidate. XXXX full rights for all is no good */ - if (strcmp(filename2, candidate_db) == 0) - chmod(filename2, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH); - if (send_msg_ok(s) < 0) - goto done; - retval = 0; - done: - return retval; -} - -/*! Internal message: Lock database - * @param[in] h Clicon handle - * @param[in] s Client socket where request arrived, and where replies are sent - * @param[in] pid Client 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_lock(clicon_handle h, - int s, - int pid, - struct clicon_msg *msg, - const char *label) -{ - char *db; - int retval = -1; - char *candidate_db; - - - if (clicon_msg_lock_decode(msg, - &db, - label) < 0){ - send_msg_err(s, clicon_errno, clicon_suberrno, - clicon_err_reason); - goto done; - } - if ((candidate_db = clicon_candidate_db(h)) == NULL){ - send_msg_err(s, 0, 0, "candidate db not set"); - goto done; - } - if (strcmp(db, candidate_db)){ - send_msg_err(s, OE_DB, 0, "can not lock %s, only %s", - db, candidate_db); - goto done; - } - if (db_islocked(h)){ - if (pid == db_islocked(h)) - ; - else{ - send_msg_err(s, OE_DB, 0, "lock failed: locked by %d", db_islocked(h)); - goto done; - } - } - else - db_lock(h, pid); - if (send_msg_ok(s) < 0) - goto done; - retval = 0; - done: - return retval; -} - -/*! Internal message: Unlock database - * @param[in] h Clicon handle - * @param[in] s Client socket where request arrived, and where replies are sent - * @param[in] pid Client 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_unlock(clicon_handle h, - int s, - int pid, - struct clicon_msg *msg, - const char *label) -{ - char *db; - int retval = -1; - char *candidate_db; - - if (clicon_msg_unlock_decode(msg, - &db, - label) < 0){ - send_msg_err(s, clicon_errno, clicon_suberrno, - clicon_err_reason); - goto done; - } - if ((candidate_db = clicon_candidate_db(h)) == NULL){ - send_msg_err(s, 0, 0, "candidate db not set"); - goto done; - } - - if (strcmp(db, candidate_db)){ - send_msg_err(s, OE_DB, 0, "can not unlock %s, only %s", - db, clicon_candidate_db(h)); - goto done; - } - if (db_islocked(h)){ - if (pid == db_islocked(h)) - db_unlock(h); - else{ - send_msg_err(s, OE_DB, 0, "unlock failed: locked by %d", db_islocked(h)); - 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 @@ -798,9 +516,10 @@ from_client_kill(clicon_handle h, struct clicon_msg *msg, const char *label) { - uint32_t pid; /* other pid */ - int retval = -1; + int retval = -1; + uint32_t pid; /* other pid */ struct client_entry *ce; + char *db = "running"; /* XXX */ if (clicon_msg_kill_decode(msg, &pid, @@ -823,8 +542,8 @@ from_client_kill(clicon_handle h, } if (1 || (kill (pid, 0) != 0 && errno == ESRCH)){ /* Nothing there */ /* clear from locks */ - if (db_islocked(h) == pid) - db_unlock(h); + if (xmldb_islocked(h, db) == pid) + xmldb_unlock(h, db, pid); } else{ /* failed to kill client */ send_msg_err(s, OE_DB, 0, "failed to kill %d", pid); @@ -1017,26 +736,6 @@ 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_RM: - if (from_client_rm(h, ce->ce_s, ce->ce_pid, msg, __FUNCTION__) < 0) - goto done; - break; - case CLICON_MSG_INITDB: - if (from_client_initdb(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_LOCK: - if (from_client_lock(h, ce->ce_s, ce->ce_pid, msg, __FUNCTION__) < 0) - goto done; - break; - case CLICON_MSG_UNLOCK: - if (from_client_unlock(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_commit.c b/apps/backend/backend_commit.c index b82151a9..1c49a778 100644 --- a/apps/backend/backend_commit.c +++ b/apps/backend/backend_commit.c @@ -117,18 +117,14 @@ generic_validate(yang_spec *yspec, * fails, we just ignore the errors and proceed. Maybe we should * do something more drastic? * @param[in] h Clicon handle - * @param[in] running The current database. The original backend state - * @param[in] candidate: The candidate database. The wanted backend state */ int candidate_commit(clicon_handle h, - char *candidate, - char *running) + char *candidate) { int retval = -1; int i; cxobj *xn; - struct stat sb; void *firsterr = NULL; yang_spec *yspec; transaction_data_t *td = NULL; @@ -137,24 +133,15 @@ candidate_commit(clicon_handle h, clicon_err(OE_FATAL, 0, "No DB_SPEC"); goto done; } - /* Sanity checks that databases exists. */ - if (stat(running, &sb) < 0){ - clicon_err(OE_DB, errno, "%s", running); - goto done; - } - if (stat(candidate, &sb) < 0){ - clicon_err(OE_DB, errno, "%s", candidate); - goto done; - } /* 1. Start transaction */ if ((td = transaction_new()) == NULL) goto done; /* 2. Parse xml trees */ - if (xmldb_get(running, "/", yspec, &td->td_src) < 0) + if (xmldb_get(h, "running", "/", 0, &td->td_src, NULL, NULL) < 0) goto done; - if (xmldb_get(candidate, "/", yspec, &td->td_target) < 0) + if (xmldb_get(h, candidate, "/", 0, &td->td_target, NULL, NULL) < 0) goto done; /* 3. Compute differences */ @@ -212,18 +199,15 @@ candidate_commit(clicon_handle h, goto done; /* 8. Success: Copy candidate to running */ - if (file_cp(candidate, running) < 0){ - clicon_err(OE_UNIX, errno, "file_cp(candidate; running)"); + if (xmldb_copy(h, candidate, "running") < 0) goto done; - } /* 9. Call plugin transaction end callbacks */ plugin_transaction_end(h, td); - /* 8. Copy running back to running in case end functions updated running */ - if (file_cp(running, candidate) < 0){ + /* 8. Copy running back to candidate in case end functions updated running */ + if (xmldb_copy(h, "running", candidate) < 0){ /* ignore errors or signal major setback ? */ - clicon_err(OE_UNIX, errno, "file_cp(running, candidate)"); clicon_log(LOG_NOTICE, "Error in rollback, trying to continue"); goto done; } @@ -243,16 +227,13 @@ candidate_commit(clicon_handle h, /*! Do a diff between candidate and running, then start a validate transaction * * @param[in] h Clicon handle - * @param[in] running The current database. The original backend state * @param[in] candidate: The candidate database. The wanted backend state */ int candidate_validate(clicon_handle h, - char *candidate, - char *running) - { + char *candidate) +{ int retval = -1; - struct stat sb; yang_spec *yspec; transaction_data_t *td = NULL; int i; @@ -262,24 +243,15 @@ candidate_validate(clicon_handle h, clicon_err(OE_FATAL, 0, "No DB_SPEC"); goto done; } - /* Sanity checks that databases exists. */ - if (stat(running, &sb) < 0){ - clicon_err(OE_DB, errno, "%s", running); - goto done; - } - if (stat(candidate, &sb) < 0){ - clicon_err(OE_DB, errno, "%s", candidate); - goto done; - } /* 1. Start transaction */ if ((td = transaction_new()) == NULL) goto done; /* 2. Parse xml trees */ - if (xmldb_get(running, "/", yspec, &td->td_src) < 0) + if (xmldb_get(h, "running", "/", 0, &td->td_src, NULL, NULL) < 0) goto done; - if (xmldb_get(candidate, "/", yspec, &td->td_target) < 0) + if (xmldb_get(h, "candidate", "/", 0, &td->td_target, NULL, NULL) < 0) goto done; /* 3. Compute differences */ @@ -346,25 +318,36 @@ candidate_validate(clicon_handle h, * the commit has succeeded but an error message is returned. */ int -from_client_commit(clicon_handle h, - int s, +from_client_commit(clicon_handle h, + int s, struct clicon_msg *msg, - const char *label) + const char *label) { int retval = -1; char *candidate; char *running; uint32_t snapshot; uint32_t startup; - char *snapshot_0; char *archive_dir; char *startup_config; - if (clicon_msg_commit_decode(msg, &candidate, &running, - &snapshot, &startup, label) < 0) + if (clicon_msg_commit_decode(msg, + &candidate, + &running, + &snapshot, + &startup, + label) < 0) goto err; - if (candidate_commit(h, candidate, running) < 0){ + if (strcmp(candidate, "candidate") && strcmp(candidate, "tmp")){ + clicon_err(OE_PLUGIN, 0, "candidate is not \"candidate\" or tmp"); + goto err; + } + if (strcmp(running, "running")){ + clicon_err(OE_PLUGIN, 0, "running db is not \"running\""); + goto err; + } + if (candidate_commit(h, "candidate") < 0){ clicon_debug(1, "Commit %s failed", candidate); retval = 0; /* We ignore errors from commit, but maybe we should fail on fatal errors? */ @@ -389,8 +372,7 @@ from_client_commit(clicon_handle h, clicon_err(OE_PLUGIN, 0, "startup set but startup_config not defined"); goto err; } - snapshot_0 = chunk_sprintf(__FUNCTION__, "%s/0", archive_dir); - if (file_cp(snapshot_0, startup_config) < 0){ + if (clicon_file_copy("snapshot", "startup") < 0){ clicon_err(OE_PROTO, errno, "%s: Error when creating startup", __FUNCTION__); goto err; @@ -412,32 +394,31 @@ from_client_commit(clicon_handle h, -/* - * Call backend plugin +/*! Handle an incoming validate message from a client. */ int -from_client_validate(clicon_handle h, - int s, +from_client_validate(clicon_handle h, + int s, struct clicon_msg *msg, - const char *label) + const char *label) { - char *dbname; - char *running_db; - int retval = -1; + int retval = -1; + char *candidate; - if (clicon_msg_validate_decode(msg, &dbname, label) < 0){ + if (clicon_msg_validate_decode(msg, + &candidate, + label) < 0){ send_msg_err(s, clicon_errno, clicon_suberrno, clicon_err_reason); goto err; } - - clicon_debug(1, "Validate %s", dbname); - if ((running_db = clicon_running_db(h)) == NULL){ - clicon_err(OE_FATAL, 0, "running db not set"); - goto err; + if (strcmp(candidate, "candidate") != 0 && strcmp(candidate, "tmp") != 0){ + clicon_err(OE_PLUGIN, 0, "candidate is not \"candidate\" or tmp"); + goto err; } - if (candidate_validate(h, dbname, running_db) < 0){ - clicon_debug(1, "Validate %s failed", dbname); + clicon_debug(1, "Validate %s", candidate); + if (candidate_validate(h, candidate) < 0){ + clicon_debug(1, "Validate %s failed", candidate); retval = 0; /* We ignore errors from commit, but maybe we should fail on fatal errors? */ goto err; diff --git a/apps/backend/backend_commit.h b/apps/backend/backend_commit.h index 81c2f814..5bc1f6d4 100644 --- a/apps/backend/backend_commit.h +++ b/apps/backend/backend_commit.h @@ -29,6 +29,6 @@ */ int from_client_validate(clicon_handle h, int s, struct clicon_msg *msg, const char *label); int from_client_commit(clicon_handle h, int s, struct clicon_msg *msg, const char *label); -int candidate_commit(clicon_handle h, char *candidate, char *running); +int candidate_commit(clicon_handle h, char *candidate); #endif /* _BACKEND_COMMIT_H_ */ diff --git a/apps/backend/backend_lock.c b/apps/backend/backend_lock.c deleted file mode 100644 index c3de4bfc..00000000 --- a/apps/backend/backend_lock.c +++ /dev/null @@ -1,95 +0,0 @@ -/* - * - Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren - - This file is part of CLIXON. - - CLIXON is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - CLIXON is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with CLIXON; see the file LICENSE. If not, see - . - - */ - -#ifdef HAVE_CONFIG_H -#include "clixon_config.h" /* generated by config & autoconf */ -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* cligen */ -#include - -/* clicon */ -#include - -#include "backend_lock.h" - -/* - * Easy way out: store an integer for candidate db which contains - * the session-id of the client holding the lock. - * more general: any database - * we dont make any sanity check on who is locking. - */ -static int _db_locked = 0; - -/* - * db_lock - */ -int -db_lock(clicon_handle h, int id) -{ - _db_locked = id; - clicon_debug(1, "%s: lock db by %u", __FUNCTION__, id); - return 0; -} - -/* - * db_unlock - */ -int -db_unlock(clicon_handle h) -{ - if (!_db_locked ) - return 0; - _db_locked = 0; - return 0; -} - -/* - * db_islocked - * returns id of locker - */ -int -db_islocked(clicon_handle h) -{ - return _db_locked; -} - diff --git a/apps/backend/backend_lock.h b/apps/backend/backend_lock.h deleted file mode 100644 index f498e553..00000000 --- a/apps/backend/backend_lock.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * - Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren - - This file is part of CLIXON. - - CLIXON is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - CLIXON is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with CLIXON; see the file LICENSE. If not, see - . - - * - * Database logical lock functions. - * Only one lock (candidate_db) - * Not persistent (needs another db) - */ - -#ifndef _BACKEND_LOCK_H_ -#define _BACKEND_LOCK_H_ - -/* - * Prototypes - */ -int db_lock(clicon_handle h, int id); -int db_unlock(clicon_handle h); -int db_islocked(clicon_handle h); - -#endif /* _BACKEND_LOCK_H_ */ diff --git a/apps/backend/backend_main.c b/apps/backend/backend_main.c index 6a34e54b..a4d74bed 100644 --- a/apps/backend/backend_main.c +++ b/apps/backend/backend_main.c @@ -59,9 +59,9 @@ #include "backend_handle.h" /* Command line options to be passed to getopt(3) */ -#define BACKEND_OPTS "hD:f:d:Fzu:P:1IRCc::rg:pt" +#define BACKEND_OPTS "hD:f:d:Fzu:P:1IRCc::rg:ptx:" -/* Cannot use h after this */ +/*! Terminate. Cannot use h after this */ static int config_terminate(clicon_handle h) { @@ -85,10 +85,8 @@ config_terminate(clicon_handle h) return 0; } -/* - config_sig_term - Unlink pidfile and quit -*/ +/*! Unlink pidfile and quit + */ static void config_sig_term(int arg) { @@ -130,7 +128,8 @@ usage(char *argv0, clicon_handle h) " -r\t\tReload running database\n" " -p \t\tPrint database yang specification\n" " -t \t\tPrint alternate spec translation (eg if YANG print KEY, if KEY print YANG)\n" - " -g \tClient membership required to this group (default: %s)\n", + " -g \tClient membership required to this group (default: %s)\n" + " -x \tSet CLICON_XMLDB_RPC to 0 or 1.\n", argv0, plgdir ? plgdir : "none", confsock ? confsock : "none", @@ -138,19 +137,16 @@ usage(char *argv0, clicon_handle h) startup ? startup : "none", group ? group : "none" ); - exit(0); + exit(-1); } static int -rundb_init(clicon_handle h, char *running_db) +rundb_init(clicon_handle h) { - if (unlink(running_db) != 0 && errno != ENOENT) { - clicon_err(OE_UNIX, errno, "unlink"); + if (xmldb_delete(h, "running") != 0 && errno != ENOENT) return -1; - } - if (xmldb_init(running_db) < 0) + if (xmldb_init(h, "running") < 0) return -1; - return 0; } @@ -164,19 +160,16 @@ rundb_init(clicon_handle h, char *running_db) */ static int rundb_main(clicon_handle h, - char *app_config_file, - char *running_db) + char *app_config_file) { - char *tmp = NULL; int retval = -1; int fd = -1; - yang_spec *yspec; cxobj *xt = NULL; cxobj *xn; - if ((tmp = clicon_tmpfile(__FUNCTION__)) == NULL) + if (xmldb_init(h, "tmp") < 0) goto done; - if (file_cp(running_db, tmp) < 0){ + if (xmldb_copy(h, "running", "tmp") < 0){ clicon_err(OE_UNIX, errno, "file copy"); goto done; } @@ -186,16 +179,15 @@ rundb_main(clicon_handle h, } if (clicon_xml_parse_file(fd, &xt, "") < 0) goto done; - yspec = clicon_dbspec_yang(h); if ((xn = xml_child_i(xt, 0)) != NULL) - if (xmldb_put(tmp, xn, yspec, OP_MERGE) < 0) + if (xmldb_put(h, "tmp", xn, OP_MERGE) < 0) goto done; - if (candidate_commit(h, tmp, running_db) < 0) + if (candidate_commit(h, "tmp") < 0) + goto done; + if (xmldb_delete(h, "tmp") < 0) goto done; retval = 0; done: - if (tmp) - unlink(tmp); if (xt) xml_free(xt); if (fd != -1) @@ -204,31 +196,24 @@ done: return retval; } - static int -candb_reset(clicon_handle h, char *running_db) +candb_reset(clicon_handle h) { int retval = -1; - char *tmp = NULL; - if ((tmp = clicon_tmpfile(__FUNCTION__)) == NULL) - goto done; - if (file_cp(running_db, tmp) < 0){ + if (xmldb_copy(h, "running", "tmp") < 0){ clicon_err(OE_UNIX, errno, "file copy"); goto done; } /* Request plugins to reset system state, eg initiate running from system * -R */ - if (plugin_reset_state(h, tmp) < 0) + if (plugin_reset_state(h, "tmp") < 0) goto done; - if (candidate_commit(h, tmp, running_db) < 0) + if (candidate_commit(h, "tmp") < 0) goto done; retval = 0; done: - if (tmp) - unlink(tmp); - unchunk_group(__FUNCTION__); return retval; } @@ -299,8 +284,6 @@ main(int argc, char **argv) int foreground; int once; int init_rundb; - char *running_db; - char *candidate_db; int reload_running; int reset_state_running; int reset_state_candidate; @@ -431,6 +414,14 @@ main(int argc, char **argv) case 't' : /* Print alternative dbspec format (eg if YANG, print KEY) */ printalt++; break; + case 'x' : /* set xmldb rpc on */ + { + int i; + if (sscanf(optarg, "%d", &i) != 1) + usage(argv[0], h); + clicon_option_int_set(h, "CLICON_XMLDB_RPC", i); + } + break; default: usage(argv[0], h); break; @@ -462,7 +453,7 @@ main(int argc, char **argv) unlink(pidfile); if (sockfamily==AF_UNIX && lstat(sock, &st) == 0) unlink(sock); - exit(0); + exit(0); /* OK */ } else if (pid){ @@ -500,31 +491,21 @@ main(int argc, char **argv) if (yang_spec_main(h, stdout, printspec) < 0) goto done; - if ((running_db = clicon_running_db(h)) == NULL){ - clicon_err(OE_FATAL, 0, "running db not set"); - goto done; - } - if ((candidate_db = clicon_candidate_db(h)) == NULL){ - clicon_err(OE_FATAL, 0, "candidate db not set"); - goto done; - } /* If running exists and reload_running set, make a copy to candidate */ if (reload_running){ - if (stat(running_db, &st) && errno == ENOENT){ + if (xmldb_exists(h, "running") != 1){ clicon_log(LOG_NOTICE, "%s: -r (reload running) option given but no running_db found, proceeding without", __PROGRAM__); reload_running = 0; /* void it, so we dont commit candidate below */ } else - if (file_cp(running_db, candidate_db) < 0){ - clicon_err(OE_UNIX, errno, "FATAL: file_cp"); + if (xmldb_copy(h, "running", "candidate") < 0) goto done; - } } /* Init running db - * -I + * -I or if it isnt there */ - if (init_rundb || (stat(running_db, &st) && errno == ENOENT)) - if (rundb_init(h, running_db) < 0) + if (init_rundb || xmldb_exists(h, "running") != 1) + if (rundb_init(h) < 0) goto done; /* Initialize plugins @@ -533,12 +514,12 @@ main(int argc, char **argv) goto done; if (reset_state_candidate){ - if (candb_reset(h, running_db) < 0) + if (candb_reset(h) < 0) goto done; } else if (reset_state_running){ - if (plugin_reset_state(h, running_db) < 0) + if (plugin_reset_state(h, "running") < 0) goto done; } /* Call plugin_start */ @@ -549,7 +530,7 @@ main(int argc, char **argv) *(argv-1) = tmp; if (reload_running){ - if (candidate_commit(h, candidate_db, running_db) < 0) + if (candidate_commit(h, "candidate") < 0) goto done; } @@ -558,17 +539,16 @@ main(int argc, char **argv) -r replace running (obsolete) */ if (app_config_file) - if (rundb_main(h, app_config_file, running_db) < 0) + if (rundb_main(h, app_config_file) < 0) goto done; /* Initiate the shared candidate. Maybe we should not do this? */ - if (file_cp(running_db, candidate_db) < 0){ - clicon_err(OE_UNIX, errno, "FATAL: file_cp"); + 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; @@ -579,7 +559,7 @@ main(int argc, char **argv) clicon_log_init(__PROGRAM__, debug?LOG_DEBUG:LOG_INFO, CLICON_LOG_SYSLOG); if (daemon(0, 0) < 0){ fprintf(stderr, "config: daemon"); - exit(0); + exit(-1); } } /* Write pid-file */ diff --git a/apps/cli/cli_common.c b/apps/cli/cli_common.c index 18209696..5ede5012 100644 --- a/apps/cli/cli_common.c +++ b/apps/cli/cli_common.c @@ -69,57 +69,17 @@ static int xml2csv(FILE *f, cxobj *x, cvec *cvv); * shared - all users share a common candidate db */ int -init_candidate_db(clicon_handle h, enum candidate_db_type type) +init_candidate_db(clicon_handle h) { - int retval = -1; - struct stat sb; - char *running_db; - char *candidate_db; + int retval = -1; - if ((running_db = clicon_running_db(h)) == NULL){ - clicon_err(OE_PLUGIN, 0, "%s: RUNNING_CANDIDATE_DB option not set", __FUNCTION__); + if (xmldb_exists(h, "running") != 1){ + clicon_err(OE_FATAL, 0, "Running db does not exist"); goto err; } - if ((candidate_db = clicon_candidate_db(h)) == NULL){ - clicon_err(OE_PLUGIN, 0, "%s: CLICON_CANDIDATE_DB option not set", __FUNCTION__); - goto err; - } - cli_set_candidate_type(h, type); - switch(type){ - case CANDIDATE_DB_NONE: - break; - case CANDIDATE_DB_PRIVATE: - if (lstat(candidate_db, &sb) < 0){ - if (file_cp(running_db, candidate_db) < 0){ - clicon_err(OE_UNIX, errno, "Error when copying %s to %s", - running_db, candidate_db); - unlink(candidate_db); - goto err; - } - } - break; - case CANDIDATE_DB_SHARED: - if (lstat(running_db, &sb) < 0){ - clicon_err(OE_FATAL, 0, "Running db (%s) does not exist", - running_db); + if (xmldb_exists(h, "candidate") != 1) + if (xmldb_copy(h, "running", "candidate") < 0) goto err; - } - if (lstat(candidate_db, &sb) < 0){ - if (cli_send2backend(h)) { - clicon_rpc_copy(h, running_db, candidate_db); - } - else - if (file_cp(running_db, candidate_db) < 0){ - clicon_err(OE_UNIX, errno, "Error when copying %s to %s", - running_db, candidate_db); - goto err; - } - } - break; - case CANDIDATE_DB_CURRENT: - clicon_option_str_set(h, "CLICON_CANDIDATE_DB", running_db); - break; - } retval = 0; err: return retval; @@ -132,18 +92,6 @@ init_candidate_db(clicon_handle h, enum candidate_db_type type) int exit_candidate_db(clicon_handle h) { -// struct stat sb; - - switch(cli_candidate_type(h)){ - case CANDIDATE_DB_PRIVATE: -#if 0 /* XXX: maybe we should remove it, but I want several cli:s to edit it */ - if (lstat(clicon_candidate_db(h), &sb) == 0) - unlink(clicon_candidate_db(h)); -#endif - break; - default: - break; - } return 0; } @@ -165,10 +113,8 @@ cli_debug(clicon_handle h, cvec *vars, cg_var *arg) /* cli */ clicon_debug_init(level, NULL); /* 0: dont debug, 1:debug */ /* config daemon */ - if (cli_send2backend(h)) { - if (clicon_rpc_debug(h, level) < 0) - goto done; - } + if (clicon_rpc_debug(h, level) < 0) + goto done; done: return 0; } @@ -351,29 +297,20 @@ cli_quit(clicon_handle h, cvec *vars, cg_var *arg) return 0; } -/* - * Generic commit callback - * if arg is 1, then snapshot and copy to startup config +/*! Generic commit callback + * @param[in] arg If 1, then snapshot and copy to startup config */ int -cli_commit(clicon_handle h, cvec *vars, cg_var *arg) +cli_commit(clicon_handle h, + cvec *vars, + cg_var *arg) { int retval = -1; int snapshot = arg?cv_int32_get(arg):0; - char *candidate; - char *running; - if ((running = clicon_running_db(h)) == NULL){ - clicon_err(OE_FATAL, 0, "running db not set"); - goto done; - } - if ((candidate = clicon_candidate_db(h)) == NULL){ - clicon_err(OE_FATAL, 0, "candidate db not set"); - goto done; - } if ((retval = clicon_rpc_commit(h, - running, - candidate, + "running", + "candidate", snapshot, /* snapshot */ snapshot)) < 0){ /* startup */ cli_output(stderr, "Commit failed. Edit and try again or discard changes\n"); @@ -390,17 +327,10 @@ cli_commit(clicon_handle h, cvec *vars, cg_var *arg) int cli_validate(clicon_handle h, cvec *vars, cg_var *arg) { - char *candidate_db; int retval = -1; - if ((candidate_db = clicon_candidate_db(h)) == NULL){ - clicon_err(OE_FATAL, 0, "candidate db not set"); - return -1; - } - if (cli_send2backend(h)) { - if ((retval = clicon_rpc_validate(h, candidate_db)) < 0) - cli_output(stderr, "Validate failed. Edit and try again or discard changes\n"); - } + if ((retval = clicon_rpc_validate(h, "candidate")) < 0) + cli_output(stderr, "Validate failed. Edit and try again or discard changes\n"); return retval; } @@ -447,7 +377,6 @@ expand_dbvar_dbxml(void *h, char ***commands, char ***helptexts) { - char *dbname; int nvec; char **vec = NULL; int retval = -1; @@ -457,10 +386,11 @@ expand_dbvar_dbxml(void *h, cxobj *xt = NULL; char *xk = NULL; cxobj **xvec = NULL; + size_t xlen = 0; + cxobj *x; + char *bodystr; int i; int i0; - size_t xlen; - yang_spec *yspec; if (arg == NULL || (str = cv_string_get(arg)) == NULL){ clicon_err(OE_PLUGIN, 0, "%s: requires string argument", __FUNCTION__); @@ -472,37 +402,34 @@ expand_dbvar_dbxml(void *h, goto done; } dbstr = vec[0]; - if (strcmp(dbstr, "running") == 0) - dbname = clicon_running_db(h); - else - if (strcmp(dbstr, "candidate") == 0) - dbname = clicon_candidate_db(h); - else{ + if (strcmp(dbstr, "running") != 0 && + strcmp(dbstr, "candidate") != 0){ clicon_err(OE_PLUGIN, 0, "No such db name: %s", dbstr); goto done; } - if (dbname == NULL){ - clicon_err(OE_FATAL, 0, "db not set"); - goto done; - } xkfmt = vec[1]; /* xkfmt = /interface/%s/address/%s --> ^/interface/eth0/address/.*$ --> /interface/[name=eth0]/address */ if (xmlkeyfmt2xpath(xkfmt, cvv, &xk) < 0) - goto done; - yspec = clicon_dbspec_yang(h); - if (xmldb_get_vec(dbname, xk, yspec, &xt, &xvec, &xlen) < 0) + goto done; + if (xmldb_get(h, dbstr, xk, 1, &xt, &xvec, &xlen) < 0) goto done; i0 = *nr; *nr += xlen; if ((*commands = realloc(*commands, sizeof(char *) * (*nr))) == NULL) { - clicon_err(OE_UNDEF, errno, "realloc: %s", strerror (errno)); + clicon_err(OE_UNIX, errno, "realloc: %s", strerror (errno)); goto done; } - for (i = 0; i < xlen; i++) - (*commands)[i0+i] = strdup(xml_body(xvec[i])); + for (i = 0; i < xlen; i++) { + x = xvec[i]; + if ((bodystr = xml_body(x)) == NULL){ + clicon_err(OE_CFG, 0, "No xml body"); + goto done; + } + (*commands)[i0+i] = strdup(bodystr); + } retval = 0; done: unchunk_group(__FUNCTION__); @@ -634,14 +561,16 @@ expand_dir(char *dir, int *nr, char ***commands, mode_t flags, int detail) /*! Compare two dbs using XML. Write to file and run diff */ static int -compare_xmls(cxobj *xc1, cxobj *xc2, int astext) +compare_xmls(cxobj *xc1, + cxobj *xc2, + int astext) { - int fd; - FILE *f; - char filename1[MAXPATHLEN]; - char filename2[MAXPATHLEN]; - char cmd[MAXPATHLEN]; - int retval = -1; + int fd; + FILE *f; + char filename1[MAXPATHLEN]; + char filename2[MAXPATHLEN]; + char cmd[MAXPATHLEN]; + int retval = -1; cxobj *xc; snprintf(filename1, sizeof(filename1), "/tmp/cliconXXXXXX"); @@ -701,20 +630,10 @@ compare_dbs(clicon_handle h, cvec *cvv, cg_var *arg) cxobj *xc1 = NULL; /* running xml */ cxobj *xc2 = NULL; /* candidate xml */ int retval = -1; - char *running; - char *candidate; - if ((running = clicon_running_db(h)) == NULL){ - clicon_err(OE_FATAL, 0, "running db not set"); + if (xmldb_get(h, "running", "/", 0, &xc1, NULL, NULL) < 0) goto done; - } - if ((candidate = clicon_candidate_db(h)) == NULL){ - clicon_err(OE_FATAL, 0, "candidate db not set"); - goto done; - } - if (xmldb_get(running, "/", clicon_dbspec_yang(h), &xc1) < 0) - goto done; - if (xmldb_get(candidate, "/", clicon_dbspec_yang(h), &xc2) < 0) + if (xmldb_get(h, "candidate", "/", 0, &xc2, NULL, NULL) < 0) goto done; if (compare_xmls(xc1, xc2, arg?cv_int32_get(arg):0) < 0) /* astext? */ goto done; @@ -752,13 +671,10 @@ cli_dbxml(clicon_handle h, { int retval = -1; char *str = NULL; - char *candidate; - char *running; char *xkfmt; /* xml key format */ char *xk = NULL; /* xml key */ cg_var *cval; char *val = NULL; - yang_spec *yspec; /* * clicon_rpc_xmlput(h, db, MERGE,"eth0hej"); @@ -772,14 +688,6 @@ cli_dbxml(clicon_handle h, * Where is arg computed? In eg yang2cli_leaf, otherwise in yang_parse,.. * Create string using cbuf and save that. */ - if ((candidate = clicon_candidate_db(h)) == NULL){ - clicon_err(OE_FATAL, 0, "candidate db not set"); - return -1; - } - if ((running = clicon_candidate_db(h)) == NULL){ - clicon_err(OE_FATAL, 0, "running db not set"); - return -1; - } xkfmt = cv_string_get(arg); if (xmlkeyfmt2key(xkfmt, cvv, &xk) < 0) goto done; @@ -788,20 +696,11 @@ cli_dbxml(clicon_handle h, clicon_err(OE_UNIX, errno, "cv2str_dup"); goto done; } - if (cli_send2backend(h)) { - if (clicon_rpc_change(h, candidate, op, xk, val) < 0) + if (clicon_rpc_change(h, "candidate", op, xk, val) < 0) + goto done; + if (clicon_autocommit(h)) { + if (clicon_rpc_commit(h, "running", "candidate", 0, 0) < 0) goto done; - if (clicon_autocommit(h)) { - if (clicon_rpc_commit(h, running, candidate, 0, 0) < 0) - goto done; - } - } - else{ - yspec = clicon_dbspec_yang(h); - if (xmldb_put_xkey(candidate, xk, val, yspec, op) < 0) - goto done; - if (clicon_autocommit(h)) - clicon_log(LOG_WARNING, "Cant combine no backend and autocommit"); } retval = 0; done: @@ -863,7 +762,9 @@ cli_del(clicon_handle h, cvec *cvv, cg_var *arg) * @see save_config_file */ int -load_config_file(clicon_handle h, cvec *cvv, cg_var *arg) +load_config_file(clicon_handle h, + cvec *cvv, + cg_var *arg) { int ret = -1; struct stat st; @@ -871,7 +772,6 @@ load_config_file(clicon_handle h, cvec *cvv, cg_var *arg) char **vecp; char *filename; int replace; - char *dbname; char *str; cg_var *cv; int nvec; @@ -882,7 +782,6 @@ load_config_file(clicon_handle h, cvec *cvv, cg_var *arg) cxobj *xn; cxobj *x; cbuf *cbxml; - yang_spec *yspec; if (arg == NULL || (str = cv_string_get(arg)) == NULL){ clicon_err(OE_PLUGIN, 0, "%s: requires string argument", __FUNCTION__); @@ -916,57 +815,30 @@ load_config_file(clicon_handle h, cvec *cvv, cg_var *arg) goto done; } filename = vecp[0]; - if ((dbname = clicon_candidate_db(h)) == NULL){ - clicon_err(OE_FATAL, 0, "candidate db not set"); - goto done; - } if (stat(filename, &st) < 0){ clicon_err(OE_UNIX, 0, "load_config: stat(%s): %s\n", filename, strerror(errno)); goto done; } - if (cli_send2backend(h)) { - /* Open and parse local file into xml */ - if ((fd = open(filename, O_RDONLY)) < 0){ - clicon_err(OE_UNIX, errno, "%s: open(%s)", __FUNCTION__, filename); - goto done; - } - if (clicon_xml_parse_file(fd, &xt, "") < 0) - goto done; - if ((xn = xml_child_i(xt, 0)) != NULL){ - if ((cbxml = cbuf_new()) == NULL) - goto done; - x = NULL; - while ((x = xml_child_each(xn, x, -1)) != NULL) - if (clicon_xml2cbuf(cbxml, x, 0, 0) < 0) - goto done; - if (clicon_rpc_xmlput(h, dbname, - replace?OP_REPLACE:OP_MERGE, - cbuf_get(cbxml)) < 0) - goto done; - cbuf_free(cbxml); - } + /* Open and parse local file into xml */ + if ((fd = open(filename, O_RDONLY)) < 0){ + clicon_err(OE_UNIX, errno, "%s: open(%s)", __FUNCTION__, filename); + goto done; } - else{ - if (replace){ - if (unlink(dbname) < 0){ - clicon_err(OE_UNIX, 0, "rm %s %s", filename, strerror(errno)); - goto done; - } - if (xmldb_init(dbname) < 0) - goto done; - } - if ((fd = open(filename, O_RDONLY)) < 0){ - clicon_err(OE_UNIX, errno, "%s: open(%s)", __FUNCTION__, filename); + if (clicon_xml_parse_file(fd, &xt, "") < 0) + goto done; + if ((xn = xml_child_i(xt, 0)) != NULL){ + if ((cbxml = cbuf_new()) == NULL) goto done; - } - if (clicon_xml_parse_file(fd, &xt, "") < 0) - goto done; - yspec = clicon_dbspec_yang(h); - if ((xn = xml_child_i(xt, 0)) != NULL){ - if (xmldb_put(dbname, xn, yspec, replace?OP_REPLACE:OP_MERGE) < 0) + x = NULL; + while ((x = xml_child_each(xn, x, -1)) != NULL) + if (clicon_xml2cbuf(cbxml, x, 0, 0) < 0) goto done; - } + if (clicon_rpc_xmlput(h, "candidate", + replace?OP_REPLACE:OP_MERGE, + cbuf_get(cbxml)) < 0) + goto done; + cbuf_free(cbxml); } ret = 0; done: @@ -1001,7 +873,6 @@ save_config_file(clicon_handle h, char **vec; char **vecp; char *filename; - char *dbname; cg_var *cv; int nvec; char *str; @@ -1009,7 +880,6 @@ save_config_file(clicon_handle h, char *varstr; cxobj *xt = NULL; FILE *f = NULL; - yang_spec *yspec; if (arg == NULL || (str = cv_string_get(arg)) == NULL){ clicon_err(OE_PLUGIN, 0, "%s: requires string argument", __FUNCTION__); @@ -1025,20 +895,10 @@ save_config_file(clicon_handle h, } dbstr = vec[0]; varstr = vec[1]; - if (strcmp(dbstr, "running") == 0) - dbname = clicon_running_db(h); - else - if (strcmp(dbstr, "candidate") == 0) - dbname = clicon_candidate_db(h); - else{ + if (strcmp(dbstr, "running") != 0 && strcmp(dbstr, "candidate") != 0) { clicon_err(OE_PLUGIN, 0, "No such db name: %s", dbstr); goto done; } - if (dbname == NULL){ - clicon_err(OE_FATAL, 0, "dbname not set"); - goto done; - } - if ((cv = cvec_find_var(cvv, varstr)) == NULL){ clicon_err(OE_PLUGIN, 0, "No such var name: %s", varstr); goto done; @@ -1048,8 +908,7 @@ save_config_file(clicon_handle h, goto done; } filename = vecp[0]; - yspec = clicon_dbspec_yang(h); - if (xmldb_get(dbname, "/", yspec, &xt) < 0) + if (xmldb_get(h, dbstr, "/", 0, &xt, NULL, NULL) < 0) goto done; if ((f = fopen(filename, "wb")) == NULL){ clicon_err(OE_CFG, errno, "Creating file %s", filename); @@ -1074,7 +933,6 @@ save_config_file(clicon_handle h, int delete_all(clicon_handle h, cvec *cvv, cg_var *arg) { - char *dbname; char *dbstr; int retval = -1; @@ -1082,31 +940,14 @@ delete_all(clicon_handle h, cvec *cvv, cg_var *arg) clicon_err(OE_PLUGIN, 0, "%s: requires string argument", __FUNCTION__); goto done; } - if (strcmp(dbstr, "running") == 0) - dbname = clicon_running_db(h); - else - if (strcmp(dbstr, "candidate") == 0) - dbname = clicon_candidate_db(h); - else{ + if (strcmp(dbstr, "running") != 0 && strcmp(dbstr, "candidate") != 0){ clicon_err(OE_PLUGIN, 0, "No such db name: %s", dbstr); goto done; } - if (dbname == NULL){ - clicon_err(OE_FATAL, 0, "dbname not set"); + if (xmldb_delete(h, dbstr) < 0) + goto done; + if (xmldb_init(h, dbstr) < 0) goto done; - } - if (cli_send2backend(h)) { - clicon_rpc_rm(h, dbname); - clicon_rpc_initdb(h, dbname); - } - else{ - if (unlink(dbname) < 0){ - clicon_err(OE_FATAL, errno, "unlink(%s)", dbname); - goto done; - } - if (xmldb_init(dbname) < 0) - goto done; - } retval = 0; done: return retval; @@ -1118,22 +959,7 @@ delete_all(clicon_handle h, cvec *cvv, cg_var *arg) int discard_changes(clicon_handle h, cvec *cvv, cg_var *arg) { - char *running_db; - char *candidate_db; - int retval = -1; - - if ((candidate_db = clicon_candidate_db(h)) == NULL){ - clicon_err(OE_FATAL, 0, "candidate db not set"); - goto done; - } - if ((running_db = clicon_running_db(h)) == NULL){ - clicon_err(OE_FATAL, 0, "running db not set"); - goto done; - } - clicon_rpc_copy(h, running_db, candidate_db); - retval = 0; - done: - return retval; + return xmldb_copy(h, "running", "candidate"); } /*! Generic function for showing configurations. @@ -1157,12 +983,11 @@ show_conf_xmldb_as(clicon_handle h, cxobj **xt) /* top xml */ { int retval = -1; - char *dbname; + char *db; char **vec = NULL; int nvec; char *str; char *xpath; - yang_spec *yspec; if (arg == NULL || (str = cv_string_get(arg)) == NULL){ clicon_err(OE_PLUGIN, 0, "%s: requires string argument", __FUNCTION__); @@ -1177,22 +1002,13 @@ show_conf_xmldb_as(clicon_handle h, goto done; } /* Dont get attr here, take it from arg instead */ - if (strcmp(vec[0], "running") == 0) /* XXX: hardcoded */ - dbname = clicon_running_db(h); - else - if (strcmp(vec[0], "candidate") == 0) /* XXX: hardcoded */ - dbname = clicon_candidate_db(h); - else{ - clicon_err(OE_PLUGIN, 0, "No such db name: %s", vec[0]); - goto done; - } - if (dbname == NULL){ - clicon_err(OE_FATAL, 0, "dbname not set"); + db = vec[0]; + if (strcmp(db, "running") != 0 && strcmp(db, "candidate") != 0) { + clicon_err(OE_PLUGIN, 0, "No such db name: %s", db); goto done; } xpath = vec[1]; - yspec = clicon_dbspec_yang(h); - if (xmldb_get(dbname, xpath, yspec, xt) < 0) + if (xmldb_get(h, db, xpath, 0, xt, NULL, NULL) < 0) goto done; retval = 0; done: @@ -1272,11 +1088,8 @@ int show_conf_xpath(clicon_handle h, cvec *cvv, cg_var *arg) { int retval = -1; - char *dbname; - char **vec = NULL; char *str; char *xpath; - yang_spec *yspec; cg_var *cv; cxobj *xt = NULL; cxobj **xv = NULL; @@ -1288,23 +1101,13 @@ show_conf_xpath(clicon_handle h, cvec *cvv, cg_var *arg) goto done; } /* Dont get attr here, take it from arg instead */ - if (strcmp(str, "running") == 0) /* XXX: hardcoded */ - dbname = clicon_running_db(h); - else - if (strcmp(str, "candidate") == 0) /* XXX: hardcoded */ - dbname = clicon_candidate_db(h); - else{ - clicon_err(OE_PLUGIN, 0, "No such db name: %s", vec[0]); - goto done; - } - if (dbname == NULL){ - clicon_err(OE_FATAL, 0, "dbname not set"); + if (strcmp(str, "running") != 0 && strcmp(str, "candidate") != 0){ + clicon_err(OE_PLUGIN, 0, "No such db name: %s", str); goto done; } cv = cvec_find_var(cvv, "xpath"); xpath = cv_string_get(cv); - yspec = clicon_dbspec_yang(h); - if (xmldb_get_vec(dbname, xpath, yspec, &xt, &xv, &xlen) < 0) + if (xmldb_get(h, str, xpath, 1, &xt, &xv, &xlen) < 0) goto done; for (i=0; icl_cligen = clih; - cl->cl_candidate_type = CANDIDATE_DB_SHARED; h = (clicon_handle)cl; done: return h; @@ -120,43 +117,8 @@ cli_handle_exit(clicon_handle h) /*---------------------------------------------------------- * cli-specific handle access functions *----------------------------------------------------------*/ -/*! Send changes to configuration daemon or let client handle it itself. Default is 1 */ -int -cli_set_send2backend(clicon_handle h, int send2backend) -{ - struct cli_handle *cl = handle(h); - cl->cl_send2backend = send2backend; - return 0; -} - -/*! Get status of whether to send changes to configuration daemon. */ -int -cli_send2backend(clicon_handle h) -{ - struct cli_handle *cl = handle(h); - - return cl->cl_send2backend; -} - -enum candidate_db_type -cli_candidate_type(clicon_handle h) -{ - struct cli_handle *cl = handle(h); - - return cl->cl_candidate_type; -} - -int -cli_set_candidate_type(clicon_handle h, enum candidate_db_type type) -{ - struct cli_handle *cl = handle(h); - - cl->cl_candidate_type = type; - return 0; -} - -/* Current syntax-group */ +/*! Get current syntax-group */ cli_syntax_t * cli_syntax(clicon_handle h) { @@ -164,8 +126,10 @@ cli_syntax(clicon_handle h) return cl->cl_stx; } +/*! Set current syntax-group */ int -cli_syntax_set(clicon_handle h, cli_syntax_t *stx) +cli_syntax_set(clicon_handle h, + cli_syntax_t *stx) { struct cli_handle *cl = handle(h); cl->cl_stx = stx; diff --git a/apps/cli/cli_main.c b/apps/cli/cli_main.c index fccf7d03..838b0620 100644 --- a/apps/cli/cli_main.c +++ b/apps/cli/cli_main.c @@ -56,7 +56,7 @@ #include "cli_handle.h" /* Command line options to be passed to getopt(3) */ -#define CLI_OPTS "hD:f:F:1u:d:m:cP:qpGLl:" +#define CLI_OPTS "hD:f:F:1u:d:m:qpGLl:" /*! terminate cli application */ static int @@ -92,6 +92,7 @@ cli_signal_init (clicon_handle h) } /*! Interactive CLI command loop + * @param[in] h CLICON handle * @see cligen_loop */ static void @@ -132,8 +133,6 @@ usage(char *argv0, clicon_handle h) "\t-u \tconfig UNIX domain path (default: %s)\n" "\t-d \tSpecify plugin directory (default: %s)\n" "\t-m \tSpecify plugin syntax mode\n" - "\t-c \t\tWrite to candidate db directly, not via config backend\n" - "\t-P \tWrite to private database\n" "\t-q \t\tQuiet mode, dont print greetings or prompt, terminate on ctrl-C\n" "\t-p \t\tPrint database yang specification\n" "\t-G \t\tPrint CLI syntax generated from dbspec (if CLICON_CLI_GENMODEL enabled)\n" @@ -152,8 +151,6 @@ int main(int argc, char **argv) { char c; - enum candidate_db_type dbtype; - char private_db[MAXPATHLEN]; int once; char *tmp; char *argv0 = argv[0]; @@ -163,8 +160,8 @@ main(int argc, char **argv) int logclisyntax = 0; int help = 0; char *treename; - char *running_db; int logdst = CLICON_LOG_STDERR; + char *restarg; /* what remains after options */ /* Defaults */ @@ -175,10 +172,7 @@ main(int argc, char **argv) goto done; if (cli_plugin_init(h) != 0) goto done; - dbtype = CANDIDATE_DB_SHARED; once = 0; - private_db[0] = '\0'; - cli_set_send2backend(h, 1); /* send changes to config daemon */ cli_set_comment(h, '#'); /* Default to handle #! clicon_cli scripts */ /* @@ -269,13 +263,6 @@ main(int argc, char **argv) usage(argv[0], h); clicon_option_str_set(h, "CLICON_CLI_MODE", optarg); break; - case 'c' : /* No config daemon (used in bootstrapping and file load) */ - cli_set_send2backend(h, 0); - break; - case 'P' : /* load to private database with given name */ - dbtype = CANDIDATE_DB_PRIVATE; - clicon_option_str_set(h, "CLICON_CANDIDATE_DB", optarg); /* override default */ - break; case 'q' : /* Quiet mode */ clicon_option_str_set(h, "CLICON_QUIET", "on"); break; @@ -359,25 +346,12 @@ main(int argc, char **argv) goto done; } - /* Initialize databases */ - if ((running_db = clicon_running_db(h)) == NULL) - goto done; - - if (strlen(private_db)) - clicon_option_str_set(h, "CLICON_CANDIDATE_DB", private_db); - - if (!cli_send2backend(h)) - if (xmldb_init(running_db) < 0){ - fprintf (stderr, "FATAL: Could not init running_db. (Run as root?)\n"); - goto done; - } /* A client does not have access to the candidate (and running) databases if both these conditions are true: 1. clicon_sock_family(h) == AF_INET[6] - 2. cli_send2backend(h) == 1 */ - if (clicon_sock_family(h) == AF_UNIX || cli_send2backend(h)==0) - if (init_candidate_db(h, dbtype) < 0) + if (clicon_sock_family(h) == AF_UNIX) + if (init_candidate_db(h) < 0) return -1; if (logclisyntax) @@ -386,19 +360,29 @@ main(int argc, char **argv) if (debug) clicon_option_dump(h, debug); + + /* Join rest of argv to a single command */ + restarg = clicon_strjoin(argc, argv, " ", __FUNCTION__); + /* Call start function in all plugins before we go interactive Pass all args after the standard options to plugin_start */ - tmp = *(argv-1); *(argv-1) = argv0; cli_plugin_start(h, argc+1, argv-1); *(argv-1) = tmp; /* Launch interfactive event loop, unless -1 */ - if (once == 0) + if (restarg != NULL && strlen(restarg)){ + char *mode = cli_syntax_mode(h); + int result; + clicon_parse(h, restarg, &mode, &result); + } + /* Go into event-loop unless -1 command-line */ + if (!once) cli_interactive(h); done: + unchunk_group(__FUNCTION__); // Gets in your face if we log on stderr clicon_log_init(__PROGRAM__, LOG_INFO, 0); /* Log on syslog no stderr */ clicon_log(LOG_NOTICE, "%s: %u Terminated\n", __PROGRAM__, getpid()); diff --git a/apps/cli/clixon_cli_api.h b/apps/cli/clixon_cli_api.h index 122b66d7..1f75e1fe 100644 --- a/apps/cli/clixon_cli_api.h +++ b/apps/cli/clixon_cli_api.h @@ -31,18 +31,6 @@ #define CLI_PROMPT_LEN 64 #define CLI_DEFAULT_PROMPT ">" -/* - * Types - */ -//typedef void *cli_handle; /* clicon cli handle, see struct cli_handle */ -enum candidate_db_type{ - CANDIDATE_DB_NONE, /* No candidate */ - CANDIDATE_DB_PRIVATE, /* Create a private candidate_db */ - CANDIDATE_DB_SHARED, /* Share the candidate with everyone else */ - CANDIDATE_DB_CURRENT /* Dont create candidate, use current directly */ -}; - - /* * Function Declarations */ @@ -62,16 +50,12 @@ char cli_set_comment(clicon_handle h, char c); char cli_comment(clicon_handle h); int cli_set_exiting(clicon_handle h, int exiting); int cli_exiting(clicon_handle h); -int cli_set_send2backend(clicon_handle h, int send2backend); -int cli_send2backend(clicon_handle h); clicon_handle cli_handle_init(void); int cli_handle_exit(clicon_handle h); cligen_handle cli_cligen(clicon_handle h); -enum candidate_db_type cli_candidate_type(clicon_handle h); -int cli_set_candidate_type(clicon_handle h, enum candidate_db_type type); /* cli_common.c */ -int init_candidate_db(clicon_handle h, enum candidate_db_type type); +int init_candidate_db(clicon_handle h); int exit_candidate_db(clicon_handle h); #define cli_output cligen_output int cli_set (clicon_handle h, cvec *vars, cg_var *arg); diff --git a/apps/dbctrl/dbctrl_main.c b/apps/dbctrl/dbctrl_main.c index 2383f88e..e9126f67 100644 --- a/apps/dbctrl/dbctrl_main.c +++ b/apps/dbctrl/dbctrl_main.c @@ -50,7 +50,7 @@ #include /* Command line options to be passed to getopt(3) */ -#define DBCTRL_OPTS "hDd:pbn:r:m:Zi" +#define DBCTRL_OPTS "hDSd:pbn:r:m:Zi" /* * remove_entry @@ -65,8 +65,7 @@ remove_entry(char *dbname, char *key) #endif } -/* - * usage +/*! usage */ static void usage(char *argv0) @@ -75,7 +74,8 @@ usage(char *argv0) "where options are\n" "\t-h\t\tHelp\n" "\t-D\t\tDebug\n" - "\t-d \tDatabase name (default: running_db)\n" + "\t-S\t\tLog on syslog\n" + "\t-d \tDatabase name (default: running)\n" "\t-p\t\tDump database on stdout\n" "\t-b\t\tBrief output, just print keys. Combine with -p or -m\n" "\t-n \" \" Add database entry\n" @@ -101,9 +101,8 @@ main(int argc, char **argv) char *addstr; char rmkey[MAXPATHLEN]; int brief; - char dbname[MAXPATHLEN] = {0,}; + char db[MAXPATHLEN] = {0,}; int use_syslog; - yang_spec *yspec; clicon_handle h; /* In the startup, logs to stderr & debug flag set later */ @@ -118,6 +117,7 @@ main(int argc, char **argv) brief = 0; use_syslog = 0; addstr = NULL; + memcpy(db, "running", strlen("running")+1); memset(rmkey, '\0', sizeof(rmkey)); if ((h = clicon_handle_init()) == NULL) @@ -143,6 +143,7 @@ main(int argc, char **argv) use_syslog?CLICON_LOG_SYSLOG:CLICON_LOG_STDERR); clicon_debug_init(debug, NULL); + /* Now rest of options */ optind = 1; while ((c = getopt(argc, argv, DBCTRL_OPTS)) != -1) @@ -159,8 +160,8 @@ main(int argc, char **argv) case 'b': /* Dump/print/match database brief (combone w -p or -m) */ brief++; break; - case 'd': /* dbname */ - if (!optarg || sscanf(optarg, "%s", dbname) != 1) + case 'd': /* db either db filename or symbolic: running|candidate */ + if (!optarg || sscanf(optarg, "%s", db) != 1) usage(argv[0]); break; case 'n': /* add database entry */ @@ -189,33 +190,32 @@ main(int argc, char **argv) argc -= optind; argv += optind; - if (*dbname == '\0'){ + if (*db == '\0'){ clicon_err(OE_FATAL, 0, "database not specified (with -d ): %s"); goto done; } - yspec = clicon_dbspec_yang(h); if (dumpdb){ - if (xmldb_dump(stdout, dbname, matchkey)) { + /* Here db must be local file-path */ + if (xmldb_dump(stdout, db, matchkey)) { fprintf(stderr, "Match error\n"); goto done; } } if (addent) /* add entry */ - if (xmldb_put_xkey(dbname, addstr, NULL, yspec, OP_REPLACE) < 0) + if (xmldb_put_xkey(h, db, addstr, NULL, OP_REPLACE) < 0) goto done; if (rment) - if (remove_entry(dbname, rmkey) < 0) + if (remove_entry(db, rmkey) < 0) goto done; if (zapdb) /* remove databases */ /* XXX This assumes direct access to database */ - if (unlink(dbname) < 0){ - clicon_err(OE_FATAL, errno, "unlink %s", dbname); + if (xmldb_delete(h, db) < 0){ + clicon_err(OE_FATAL, errno, "xmldb_delete %s", db); goto done; } if (initdb) - if (xmldb_init(dbname) < 0) + if (xmldb_init(h, db) < 0) goto done; - done: return 0; } diff --git a/apps/netconf/netconf_lib.c b/apps/netconf/netconf_lib.c index 45f7a36d..6412af43 100644 --- a/apps/netconf/netconf_lib.c +++ b/apps/netconf/netconf_lib.c @@ -173,56 +173,25 @@ detect_endtag(char *tag, char ch, int *state) return retval; } -/* - * target_locked - * return 1 if locked, 0 if not. - * return clientid if locked. - */ -int -target_locked(enum target_type target, int *client) -{ - return 0; -} - -/* - * unlock_target - */ -int -unlock_target(enum target_type target) -{ - return 0; -} - -int -lock_target(enum target_type target) -{ - return 0; -} - /*! Get "target" attribute, return actual database given candidate or running * Caller must do error handling * @retval dbname Actual database file name */ char * -netconf_get_target(clicon_handle h, cxobj *xn, char *path) +netconf_get_target(clicon_handle h, + cxobj *xn, + char *path) { cxobj *x; char *target = NULL; - char *running_db; - char *candidate_db; - if ((running_db = clicon_running_db(h)) == NULL) - goto done; - if ((candidate_db = clicon_candidate_db(h)) == NULL) - goto done; if ((x = xpath_first(xn, path)) != NULL){ if (xpath_first(x, "candidate") != NULL) - target = candidate_db; + target = "candidate"; else - if (xpath_first(x, "running") != NULL) - target = running_db; + if (xpath_first(x, "running") != NULL) + target = "running"; } - done: return target; } diff --git a/apps/netconf/netconf_main.c b/apps/netconf/netconf_main.c index 6f4fd642..6967b029 100644 --- a/apps/netconf/netconf_main.c +++ b/apps/netconf/netconf_main.c @@ -61,11 +61,11 @@ /*! Process incoming packet * @param[in] h Clicon handle - * @param[in] xf Packet buffer + * @param[in] cb Packet buffer */ static int process_incoming_packet(clicon_handle h, - cbuf *xf) + cbuf *cb) { char *str; char *str0; @@ -76,23 +76,23 @@ process_incoming_packet(clicon_handle h, cbuf *xf1; clicon_debug(1, "RECV"); - clicon_debug(2, "%s: RCV: \"%s\"", __FUNCTION__, cbuf_get(xf)); - if ((str0 = strdup(cbuf_get(xf))) == NULL){ + clicon_debug(2, "%s: RCV: \"%s\"", __FUNCTION__, cbuf_get(cb)); + if ((str0 = strdup(cbuf_get(cb))) == NULL){ clicon_log(LOG_ERR, "%s: strdup: %s", __FUNCTION__, strerror(errno)); return -1; } str = str0; /* Parse incoming XML message */ if (clicon_xml_parse_string(&str, &xml_req) < 0){ - if ((xf = cbuf_new()) == NULL){ - netconf_create_rpc_error(xf, NULL, + if ((cb = cbuf_new()) == NULL){ + netconf_create_rpc_error(cb, NULL, "operation-failed", "rpc", "error", NULL, NULL); - netconf_output(1, xf, "rpc-error"); - cbuf_free(xf); + netconf_output(1, cb, "rpc-error"); + cbuf_free(cb); } else clicon_log(LOG_ERR, "%s: cbuf_new", __FUNCTION__); @@ -181,12 +181,12 @@ netconf_input_cb(int s, unsigned char buf[BUFSIZ]; int i; int len; - static cbuf *xf; /* XXX: should use ce state? */ + static cbuf *cb; /* XXX: should use ce state? */ int xml_state = 0; int retval = -1; - if (xf == NULL) - if ((xf = cbuf_new()) == NULL){ + if (cb == NULL) + if ((cb = cbuf_new()) == NULL){ clicon_err(OE_XML, errno, "%s: cbuf_new", __FUNCTION__); return retval; } @@ -209,22 +209,22 @@ netconf_input_cb(int s, for (i=0; i]]>", buf[i], &xml_state)) { /* OK, we have an xml string from a client */ - if (process_incoming_packet(h, xf) < 0){ + if (process_incoming_packet(h, cb) < 0){ goto done; } if (cc_closed) break; - cbuf_reset(xf); + cbuf_reset(cb); } } retval = 0; done: - // cbuf_free(xf); + // cbuf_free(cb); if (cc_closed) retval = -1; return retval; @@ -255,16 +255,15 @@ send_hello(int s) return retval; } -/* from init_candidate_db() and clicon_rpc_copy() */ +/*! Initialize candidate database */ static int -init_candidate_db(clicon_handle h, char *running_db, char *candidate_db) +init_candidate_db(clicon_handle h) { - struct stat sb; int retval = -1; /* init shared candidate */ - if (lstat(candidate_db, &sb) < 0){ - if (clicon_rpc_copy(h, running_db, candidate_db) < 0) + if (xmldb_exists(h, "candidate") != 1){ + if (xmldb_copy(h, "running", "candidate") < 0) goto done; } retval = 0; @@ -316,8 +315,6 @@ main(int argc, char **argv) int quiet = 0; clicon_handle h; int use_syslog; - char *running_db; - char *candidate_db; /* Defaults */ use_syslog = 0; @@ -390,15 +387,7 @@ main(int argc, char **argv) if (netconf_plugin_load(h) < 0) return -1; - if ((running_db = clicon_running_db(h)) == NULL){ - clicon_err(OE_FATAL, 0, "running db not set"); - goto done; - } - if ((candidate_db = clicon_candidate_db(h)) == NULL){ - clicon_err(OE_FATAL, 0, "candidate db not set"); - goto done; - } - if (init_candidate_db(h, running_db, candidate_db) < 0) + if (init_candidate_db(h) < 0) return -1; /* Call start function is all plugins before we go interactive */ tmp = *(argv-1); diff --git a/apps/netconf/netconf_rpc.c b/apps/netconf/netconf_rpc.c index a5874cb3..506473f4 100644 --- a/apps/netconf/netconf_rpc.c +++ b/apps/netconf/netconf_rpc.c @@ -108,14 +108,13 @@ netconf_filter_xmldb(clicon_handle h, cxobj *xc; cxobj *xfilterconf = NULL; int retval = -1; - yang_spec *ys = clicon_dbspec_yang(h); char *selector; /* Default subtree filter */ switch (foption){ case FILTER_SUBTREE: /* Get the whole database as xml */ - if (xmldb_get(source, NULL, ys, &xdb) < 0){ + if (xmldb_get(h, source, NULL, 0, &xdb, NULL, NULL) < 0){ netconf_create_rpc_error(cb_err, xorig, "operation-failed", "application", @@ -154,7 +153,7 @@ netconf_filter_xmldb(clicon_handle h, break; case FILTER_XPATH: selector = xml_find_value(xfilter, "select"); - if (xmldb_get(source, selector, ys, &xdb) < 0){ + if (xmldb_get(h, source, selector, 0, &xdb, NULL, NULL) < 0){ netconf_create_rpc_error(cb_err, xorig, "operation-failed", "application", @@ -202,13 +201,13 @@ netconf_filter_xmldb(clicon_handle h, - <( candidate | running )/> + | - <( candidate | running )/> + | @@ -220,24 +219,6 @@ netconf_filter_xmldb(clicon_handle h, ]]>]]> - * Call graph, client to backend and formats - * netconf_input_cb # client - * read - * process_incoming_packet # - * clicon_xml_parse_string # - * netconf_rpc_dispatch - * netconf_get_config # - * xpath_first - * netconf_filter # - * db2xml_key # "^.*$" - * clicon_dbitems # (db) - * db_regexp # (lvec) - * lvec2cvec # (cvec) - * cvec2xml # (xml) - * clicon_xml2cbuf # (xml->char*) - * wanted: - * netconf_get_config - * xpath(db, filter) */ int netconf_get_config(clicon_handle h, @@ -276,7 +257,7 @@ netconf_get_config(clicon_handle h, /*! Get options from netconf edit-config * - * XXX + * ... * (merge | none | replace) * (stop-on-error | continue-on-error ) * (set | test-then-set | test-only) @@ -418,20 +399,12 @@ netconf_edit_config(clicon_handle h, cxobj *xc; /* config */ cxobj *xcc; /* child of config */ char *target; /* db */ - char *candidate_db; cbuf *cbxml = NULL; char *xmlstr; - if ((candidate_db = clicon_candidate_db(h)) == NULL){ - netconf_create_rpc_error(cb_err, xorig, - "operation-failed", - "protocol", "error", - NULL, "Internal error"); - goto done; - } /* must have target, and it should be candidate */ if ((target = netconf_get_target(h, xn, "target")) == NULL || - strcmp(target, candidate_db)){ + strcmp(target, "candidate")){ netconf_create_rpc_error(cb_err, xorig, "missing-element", "protocol", @@ -532,7 +505,7 @@ netconf_copy_config(clicon_handle h, goto done; } #endif - if (clicon_rpc_copy(h, source, target) < 0){ + if (xmldb_copy(h, source, target) < 0){ netconf_create_rpc_error(cb_err, xorig, "operation-failed", "protocol", "error", @@ -546,7 +519,7 @@ netconf_copy_config(clicon_handle h, return retval; } -/* +/*! Delete configuration @@ -564,15 +537,6 @@ netconf_delete_config(clicon_handle h, { char *target; /* filenames */ int retval = -1; - char *candidate_db; - - if ((candidate_db = clicon_candidate_db(h)) == NULL){ - netconf_create_rpc_error(cb_err, xorig, - "operation-failed", - "protocol", "error", - NULL, "Internal error"); - goto done; - } if ((target = netconf_get_target(h, xn, "target")) == NULL){ netconf_create_rpc_error(cb_err, xorig, @@ -583,7 +547,7 @@ netconf_delete_config(clicon_handle h, "target"); goto done; } - if (strcmp(target, candidate_db)){ + if (strcmp(target, "candidate")){ netconf_create_rpc_error(cb_err, xorig, "bad-element", "protocol", @@ -592,14 +556,14 @@ netconf_delete_config(clicon_handle h, "target"); goto done; } - if (clicon_rpc_rm(h, target) < 0){ + if (xmldb_delete(h, target) < 0){ netconf_create_rpc_error(cb_err, xorig, "operation-failed", "protocol", "error", NULL, "Internal error"); goto done; } - if (clicon_rpc_initdb(h, target) < 0){ + if (xmldb_init(h, target) < 0){ netconf_create_rpc_error(cb_err, xorig, "operation-failed", "protocol", "error", @@ -612,7 +576,7 @@ netconf_delete_config(clicon_handle h, return retval; } -/* +/*! Close a (user) session */ int @@ -626,12 +590,13 @@ netconf_close_session(cxobj *xn, return 0; } -/* +/*! Lock a database + XXX */ int netconf_lock(clicon_handle h, @@ -652,40 +617,20 @@ netconf_lock(clicon_handle h, "source"); goto done; } -#ifdef notyet - if (target_locked(&client) > 0){ - snprintf(info, 64, "%d", client); - netconf_create_rpc_error(cb_err, xorig, - "lock-denied", - "protocol", - "error", - "Lock failed, lock is already held", - info); - return -1; - } - if (lock_target(target) < 0){ - netconf_create_rpc_error(cb_err, xorig, - "lock-denied", - "protocol", - "error", - "Lock failed, lock is already held", - NULL); - return -1; - } -#endif netconf_ok_set(1); retval = 0; done: return retval; } -/* +/*! Unlock a database + XXX */ int netconf_unlock(clicon_handle h, @@ -705,47 +650,18 @@ netconf_unlock(clicon_handle h, "target"); goto done; } -#ifdef notyet - if (target_locked(&client) == 0){ - netconf_create_rpc_error(cb_err, xorig, - "lock-denied", - "protocol", - "error", - "Unlock failed, lock is not held", - NULL); - return -1; - } - - if (client != ce_nr){ - snprintf(info, 64, "%d", client); - netconf_create_rpc_error(cb_err, xorig, - "lock-denied", - "protocol", - "error", - "Unlock failed, lock is held by other entity", - info); - return -1; - } - if (unlock_target(target) < 0){ - netconf_create_rpc_error(cb_err, xorig, - "lock-denied", - "protocol", - "error", - "Unlock failed, unkown reason", - NULL); - return -1; - } -#endif /* notyet */ + /* XXX notyet */ netconf_ok_set(1); retval = 0; done: return retval; } -/* +/*! Kill other user sessions PID + XXX */ int netconf_kill_session(cxobj *xn, cbuf *cb, cbuf *cb_err, cxobj *xorig) @@ -793,7 +709,7 @@ netconf_kill_session(cxobj *xn, cbuf *cb, cbuf *cb_err, cxobj *xorig) return 0; } -/* +/*! Commit candidate -> running :candidate */ @@ -805,25 +721,8 @@ netconf_commit(clicon_handle h, cxobj *xorig) { int retval = -1; - char *candidate_db; - char *running_db; - if ((candidate_db = clicon_candidate_db(h)) == NULL){ - netconf_create_rpc_error(cb_err, xorig, - "operation-failed", - "protocol", "error", - NULL, "Internal error: candidate not set"); - goto done; - } - if ((running_db = clicon_running_db(h)) == NULL){ - netconf_create_rpc_error(cb_err, xorig, - "operation-failed", - "protocol", "error", - NULL, "Internal error: running not set"); - goto done; - } - if (clicon_rpc_commit(h, candidate_db, - running_db, + if (clicon_rpc_commit(h, "candidate", "running", 1, 1) < 0){ netconf_create_rpc_error(cb_err, xorig, "operation-failed", @@ -838,7 +737,7 @@ netconf_commit(clicon_handle h, return retval; } -/* +/*! Discard all changes in candidate / revert to running :candidate */ @@ -850,24 +749,8 @@ netconf_discard_changes(clicon_handle h, cxobj *xorig) { int retval = -1; - char *running_db; - char *candidate_db; - if ((running_db = clicon_running_db(h)) == NULL){ - netconf_create_rpc_error(cb_err, xorig, - "operation-failed", - "protocol", "error", - NULL, "Internal error: running not set"); - goto done; - } - if ((candidate_db = clicon_candidate_db(h)) == NULL){ - netconf_create_rpc_error(cb_err, xorig, - "operation-failed", - "protocol", "error", - NULL, "Internal error"); - goto done; - } - if (clicon_rpc_copy(h, running_db, candidate_db) < 0){ + if (xmldb_copy(h, "running", "candidate") < 0){ netconf_create_rpc_error(cb_err, xorig, "operation-failed", "protocol", "error", @@ -881,7 +764,7 @@ netconf_discard_changes(clicon_handle h, return retval; } -/* +/*! Check the semantic consistency of candidate :validate */ diff --git a/clixon.conf.cpp.cpp b/clixon.conf.cpp.cpp index f68ae253..94b588fc 100644 --- a/clixon.conf.cpp.cpp +++ b/clixon.conf.cpp.cpp @@ -45,12 +45,6 @@ CLICON_YANG_DIR prefix/share/APPNAME/yang # This option is only relevant if CLICON_DBSPEC_TYPE is YANG CLICON_YANG_MODULE_REVISION -# Candidate qdbm database -CLICON_CANDIDATE_DB localstatedir/APPNAME/candidate_db - -# Running qdbm database -CLICON_RUNNING_DB localstatedir/APPNAME/running_db - # Location of backend .so plugins CLICON_BACKEND_DIR libdir/APPNAME/backend @@ -108,8 +102,18 @@ CLICON_BACKEND_PIDFILE localstatedir/APPNAME/APPNAME.pidfile # How to generate and show CLI syntax: VARS|ALL # CLICON_CLI_GENMODEL_TYPE VARS -# Comment character in CLI -# CLICON_CLI_COMMENT # +# Directory where "running" and "candidate" are placed +CLICON_XMLDB_DIR localstatedir/APPNAME + +# Set if xmldb runs in a separate process (clixon_xmldb). +# If set, also set xmldb_addr and xmldb_port below +# CLICON_XMLDB_RPC 0 + +# xmldb inet address (if CLICON_XMLDB_RPC) +# CLICON_XMLDB_ADDR + +# xmldb tcp port (if CLICON_XMLDB_RPC) +# CLICON_XMLDB_PORT # Dont include keys in cvec in cli vars callbacks, ie a & k in 'a k ' ignored # CLICON_CLI_VARONLY 1 diff --git a/clixon.mk.cpp b/clixon.mk.cpp index 11d3cee4..036bb87a 100644 --- a/clixon.mk.cpp +++ b/clixon.mk.cpp @@ -29,19 +29,19 @@ clixon_DBSPECDIR=prefix/share/$(APPNAME) clixon_SYSCONFDIR=sysconfdir clixon_LOCALSTATEDIR=localstatedir/$(APPNAME) clixon_LIBDIR=libdir/$(APPNAME) -clixon_DATADIR=datadir/clicon +clixon_DATADIR=datadir/clixon -# Rules for the clicon application configuration file. -# The clicon applications should be started with this fileas its -f argument. +# Rules for the clixon application configuration file. +# The clixon applications should be started with this fileas its -f argument. # Typically installed in sysconfdir # Example: APPNAME=myapp --> clixon_cli -f /usr/local/etc/myapp.conf # The two variants are if there is a .conf.local file or not .PHONY: $(APPNAME).conf ifneq (,$(wildcard ${APPNAME}.conf.local)) -${APPNAME}.conf: ${clixon_DATADIR}/clicon.conf.cpp ${APPNAME}.conf.local +${APPNAME}.conf: ${clixon_DATADIR}/clixon.conf.cpp ${APPNAME}.conf.local $(CPP) -P -x assembler-with-cpp -DAPPNAME=$(APPNAME) $< > $@ cat ${APPNAME}.conf.local >> $@ else -${APPNAME}.conf: ${clixon_DATADIR}/clicon.conf.cpp +${APPNAME}.conf: ${clixon_DATADIR}/clixon.conf.cpp $(CPP) -P -x assembler-with-cpp -DAPPNAME=$(APPNAME) $< > $@ endif diff --git a/configure b/configure index 5ab61f29..1e890817 100755 --- a/configure +++ b/configure @@ -4193,7 +4193,7 @@ fi -ac_config_files="$ac_config_files Makefile lib/Makefile lib/src/Makefile lib/clixon/Makefile apps/Makefile apps/cli/Makefile apps/backend/Makefile apps/netconf/Makefile apps/dbctrl/Makefile include/Makefile etc/Makefile etc/clixonrc example/Makefile example/docker/Makefile docker/Makefile docker/cli/Makefile docker/cli/Dockerfile docker/backend/Makefile docker/backend/Dockerfile docker/netconf/Makefile docker/netconf/Dockerfile doc/Makefile" +ac_config_files="$ac_config_files Makefile lib/Makefile lib/src/Makefile lib/clixon/Makefile apps/Makefile apps/cli/Makefile apps/backend/Makefile apps/netconf/Makefile apps/dbctrl/Makefile apps/xmldb/Makefile include/Makefile etc/Makefile etc/clixonrc example/Makefile example/docker/Makefile docker/Makefile docker/cli/Makefile docker/cli/Dockerfile docker/backend/Makefile docker/backend/Dockerfile docker/netconf/Makefile docker/netconf/Dockerfile doc/Makefile" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure @@ -4895,6 +4895,7 @@ do "apps/backend/Makefile") CONFIG_FILES="$CONFIG_FILES apps/backend/Makefile" ;; "apps/netconf/Makefile") CONFIG_FILES="$CONFIG_FILES apps/netconf/Makefile" ;; "apps/dbctrl/Makefile") CONFIG_FILES="$CONFIG_FILES apps/dbctrl/Makefile" ;; + "apps/xmldb/Makefile") CONFIG_FILES="$CONFIG_FILES apps/xmldb/Makefile" ;; "include/Makefile") CONFIG_FILES="$CONFIG_FILES include/Makefile" ;; "etc/Makefile") CONFIG_FILES="$CONFIG_FILES etc/Makefile" ;; "etc/clixonrc") CONFIG_FILES="$CONFIG_FILES etc/clixonrc" ;; diff --git a/configure.ac b/configure.ac index e6061263..5acd6903 100644 --- a/configure.ac +++ b/configure.ac @@ -163,6 +163,7 @@ AC_OUTPUT(Makefile apps/backend/Makefile apps/netconf/Makefile apps/dbctrl/Makefile + apps/xmldb/Makefile include/Makefile etc/Makefile etc/clixonrc diff --git a/example/routing.conf.local b/example/routing.conf.local index 626d0e6a..6b950c66 100644 --- a/example/routing.conf.local +++ b/example/routing.conf.local @@ -25,3 +25,14 @@ CLICON_CLI_GENMODEL_COMPLETION 1 # How to generate and show CLI syntax: VARS|ALL # CLICON_CLI_GENMODEL_TYPE VARS CLICON_CLI_GENMODEL_TYPE VARS + +# Set if xmldb runs in a separate process (clixon_xmldb). +# Also set addr and port below +CLICON_XMLDB_RPC 0 + +# xmldb inet address (if CLICON_XMLDB_RPC) +CLICON_XMLDB_ADDR 127.0.0.1 + +# xmldb tcp port (if CLICON_XMLDB_RPC) +CLICON_XMLDB_PORT 7878 + diff --git a/example/routing_cli.c b/example/routing_cli.c index adecda19..a465f5a7 100644 --- a/example/routing_cli.c +++ b/example/routing_cli.c @@ -61,7 +61,6 @@ mycallback(clicon_handle h, cvec *cvv, cg_var *arg) { int retval = -1; cxobj *xt = NULL; - yang_spec *yspec; cg_var *myvar; /* Access cligen callback variables */ @@ -70,11 +69,10 @@ mycallback(clicon_handle h, cvec *cvv, cg_var *arg) cli_output(stderr, "arg = %s\n", cv_string_get(arg)); /* get string value */ /* Show eth0 interfaces config using XPATH */ - yspec = clicon_dbspec_yang(h); - if (xmldb_get(clicon_candidate_db(h), + if (xmldb_get(h, "candidate", "/interfaces/interface[name=eth0]", - yspec, - &xt) < 0) + 0, + &xt, NULL, NULL) < 0) goto done; clicon_xml2file(stdout, xt, 0, 1); retval = 0; diff --git a/lib/clixon/clixon_file.h b/lib/clixon/clixon_file.h index 4e9d134c..72d70f8a 100644 --- a/lib/clixon/clixon_file.h +++ b/lib/clixon/clixon_file.h @@ -31,6 +31,6 @@ int clicon_file_dirent(const char *dir, struct dirent **ent, char *clicon_tmpfile(const char *label); -int file_cp(char *src, char *target); +int clicon_file_copy(char *src, char *target); #endif /* _CLIXON_FILE_H_ */ diff --git a/lib/clixon/clixon_options.h b/lib/clixon/clixon_options.h index d25730c1..c101469a 100644 --- a/lib/clixon/clixon_options.h +++ b/lib/clixon/clixon_options.h @@ -76,8 +76,6 @@ char *clicon_configfile(clicon_handle h); char *clicon_yang_dir(clicon_handle h); char *clicon_yang_module_main(clicon_handle h); char *clicon_yang_module_revision(clicon_handle h); -char *clicon_running_db(clicon_handle h); -char *clicon_candidate_db(clicon_handle h); char *clicon_backend_dir(clicon_handle h); char *clicon_cli_dir(clicon_handle h); char *clicon_clispec_dir(clicon_handle h); @@ -97,6 +95,11 @@ int clicon_cli_varonly(clicon_handle h); int clicon_cli_varonly_set(clicon_handle h, int val); int clicon_cli_genmodel_completion(clicon_handle h); +char *clicon_xmldb_dir(clicon_handle h); +int clicon_xmldb_rpc(clicon_handle h); +char *clicon_xmldb_addr(clicon_handle h); +uint16_t clicon_xmldb_port(clicon_handle h); + char *clicon_quiet_mode(clicon_handle h); enum genmodel_type clicon_cli_genmodel_type(clicon_handle h); diff --git a/lib/clixon/clixon_proto.h b/lib/clixon/clixon_proto.h index fa11aa2c..ad260409 100644 --- a/lib/clixon/clixon_proto.h +++ b/lib/clixon/clixon_proto.h @@ -39,16 +39,16 @@ enum clicon_msg_type{ current state, set running_db. Body is: 1. uint32: (1)snapshot while doing commit, (0) dont 2. uint32: (1)save to startup-config, (0) dont - 3. string: name of 'from' database (eg candidate) - 4. string: name of 'to' database (eg current) + 3. string: name of 'from' database (eg "candidate") + 4. string: name of 'to' database (eg "running") */ - CLICON_MSG_VALIDATE, /* Validate settings in a database. Body is: - 1. string: name of database + CLICON_MSG_VALIDATE, /* Validate settings in a database. Body is: + 1. string: name of database (eg "candidate") */ CLICON_MSG_CHANGE, /* Change a (single) database entry: 1. uint32: operation: OP_MERGE/OP_REPLACE/OP_REMOVE 2. uint32: length of value string - 3. string: name of database to change (eg current) + 3. string: name of database to change (eg "running") 4. string: key 5. string: value */ @@ -71,26 +71,6 @@ 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_RM , /* Delete file. Body is: - 1. string: filename to delete - */ - - CLICON_MSG_INITDB , /* (Re-)Initialize a database. Body is: - 1. string: filename of db to initialize - */ - CLICON_MSG_LOCK , /* Lock a database. Body is - 1. name of db - The reply will be OK, or ERROR. If error is - lock-denied, the session-id of the locking - entity is returned (cf netconf) - */ - CLICON_MSG_UNLOCK , /* Unlock a database. Body is: - 1. name of db * - */ 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 a1406b92..89f8df1f 100644 --- a/lib/clixon/clixon_proto_client.h +++ b/lib/clixon/clixon_proto_client.h @@ -39,11 +39,6 @@ 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 *filename1, char *filename2); -int clicon_rpc_rm(clicon_handle h, char *filename); -int clicon_rpc_initdb(clicon_handle h, char *filename); -int clicon_rpc_lock(clicon_handle h, char *dbname); -int clicon_rpc_unlock(clicon_handle h, char *dbname); 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 eb92355c..575eee59 100644 --- a/lib/clixon/clixon_proto_encode.h +++ b/lib/clixon/clixon_proto_encode.h @@ -100,40 +100,6 @@ int clicon_msg_load_decode(struct clicon_msg *msg, int *replace, char **db, char **filename, const char *label); -struct clicon_msg * -clicon_msg_initdb_encode(char *filename_src, const char *label); - -int -clicon_msg_initdb_decode(struct clicon_msg *msg, char **filename_src, - const char *label); - -struct clicon_msg * -clicon_msg_rm_encode(char *filename_src, const char *label); - -int -clicon_msg_rm_decode(struct clicon_msg *msg, char **filename_src, - const char *label); - -struct clicon_msg * -clicon_msg_copy_encode(char *filename_src, char *filename_dst, - const char *label); - -int -clicon_msg_copy_decode(struct clicon_msg *msg, - char **filename_src, char **filename_dst, - const char *label); - -struct clicon_msg * -clicon_msg_lock_encode(char *db, const char *label); - -int -clicon_msg_lock_decode(struct clicon_msg *msg, char **db, const char *label); - -struct clicon_msg * -clicon_msg_unlock_encode(char *db, const char *label); - -int -clicon_msg_unlock_decode(struct clicon_msg *msg, char **db, 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 36e4415e..e2eb9f51 100644 --- a/lib/clixon/clixon_xml_db.h +++ b/lib/clixon/clixon_xml_db.h @@ -29,16 +29,19 @@ int yang2xmlkeyfmt(yang_stmt *ys, char **xkfmt); int xmlkeyfmt2key(char *xkfmt, cvec *cvv, char **xk); int xmlkeyfmt2xpath(char *xkfmt, cvec *cvv, char **xk); -int xmlkey2xml(char *xkey, yang_spec *yspec, char **xml); -int xmldb_get(char *dbname, char *xpath, - yang_spec *yspec, cxobj **xtop); -int xmldb_get_vec(char *dbname, char *xpath, yang_spec *yspec, - cxobj **xtop, cxobj ***xvec, size_t *xlen); -int xmldb_put( char *dbname, cxobj *xt, - yang_spec *yspec, enum operation_type op); -int xmldb_put_xkey(char *dbname, char *xkey, char *val, yang_spec *yspec, +int xmldb_get(clicon_handle h, char *db, char *xpath, int vector, + cxobj **xtop, cxobj ***xvec, size_t *xlen); +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 *dbname, char *rxkey); -int xmldb_init(char *file); +int xmldb_dump(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); +int xmldb_islocked(clicon_handle h, char *db); +int xmldb_exists(clicon_handle h, char *db); +int xmldb_delete(clicon_handle h, char *db); +int xmldb_init(clicon_handle h, char *db); #endif /* _CLIXON_XML_DB_H */ diff --git a/lib/src/Makefile.in b/lib/src/Makefile.in index 95d527ef..c5967e66 100644 --- a/lib/src/Makefile.in +++ b/lib/src/Makefile.in @@ -55,7 +55,7 @@ SRC = clixon_sig.c clixon_qdb.c clixon_log.c clixon_err.c clixon_event.c \ clixon_yang.c clixon_yang_type.c \ clixon_hash.c clixon_options.c clixon_plugin.c \ clixon_proto.c clixon_proto_encode.c clixon_proto_client.c \ - clixon_xsl.c clixon_sha1.c clixon_xml_db.c + clixon_xsl.c clixon_sha1.c clixon_xml_db.c clixon_xml_db_rpc.c YACCOBJS := lex.clixon_xml_parse.o clixon_xml_parse.tab.o \ lex.clixon_yang_parse.o clixon_yang_parse.tab.o diff --git a/lib/src/clixon_err.c b/lib/src/clixon_err.c index 8e1a21b1..50ef789a 100644 --- a/lib/src/clixon_err.c +++ b/lib/src/clixon_err.c @@ -119,7 +119,7 @@ clicon_err_reset(void) * - Logs to syslog with LOG_ERR * - Set global error variable name clicon_errno * - Set global reason string clicon_err_reason - * NOTE: err direction (syslog and/or stderr) controlled by clicon_log_init() + * @note: err direction (syslog and/or stderr) controlled by clicon_log_init() * * @param fn Inline function name (when called from clicon_err() macro) * @param line Inline file line number (when called from clicon_err() macro) diff --git a/lib/src/clixon_file.c b/lib/src/clixon_file.c index 64ecd256..e5afb6dc 100644 --- a/lib/src/clixon_file.c +++ b/lib/src/clixon_file.c @@ -234,7 +234,7 @@ clicon_file_dirent(const char *dir, clicon_err(OE_UNIX, 0, "chunk: %s", strerror(errno)); goto quit; } - res = lstat (filename, &st); + res = lstat(filename, &st); unchunk (filename); if (res != 0) { clicon_err(OE_UNIX, 0, "lstat: %s", strerror(errno)); @@ -287,12 +287,13 @@ clicon_tmpfile(const char *label) return (char *)chunkdup(file, strlen(file)+1, label); } -/* - * Make a copy of file src - * On error returns -1 and sets errno. +/*! Make a copy of file src + * @retval 0 OK + * @retval -1 Error */ int -file_cp(char *src, char *target) +clicon_file_copy(char *src, + char *target) { int inF = 0, ouF = 0; int err = 0; @@ -301,16 +302,22 @@ file_cp(char *src, char *target) struct stat st; int retval = -1; - if (stat(src, &st) != 0) + if (stat(src, &st) != 0){ + clicon_err(OE_UNIX, errno, "stat"); return -1; - if((inF = open(src, O_RDONLY)) == -1) + } + if((inF = open(src, O_RDONLY)) == -1) { + clicon_err(OE_UNIX, errno, "open"); return -1; + } if((ouF = open(target, O_WRONLY | O_CREAT | O_TRUNC, st.st_mode)) == -1) { + clicon_err(OE_UNIX, errno, "open"); err = errno; goto error; } while((bytes = read(inF, line, sizeof(line))) > 0) if (write(ouF, line, bytes) < 0){ + clicon_err(OE_UNIX, errno, "write"); err = errno; goto error; } diff --git a/lib/src/clixon_log.c b/lib/src/clixon_log.c index 8f107a12..326d88d4 100644 --- a/lib/src/clixon_log.c +++ b/lib/src/clixon_log.c @@ -65,8 +65,11 @@ static FILE *_debugfile = NULL; * @param[in] ident prefix that appears on syslog (eg 'cli') * @param[in] upto log priority, eg LOG_DEBUG,LOG_INFO,...,LOG_EMERG (see syslog(3)). * @param[in] flags bitmask: if CLICON_LOG_STDERR, then print logs to stderr - if CLICON_LOG_SYSLOG, then print logs to syslog - You can do a combination of both + * if CLICON_LOG_SYSLOG, then print logs to syslog + * You can do a combination of both + * @code + * clicon_log_init(__PROGRAM__, LOG_INFO, CLICON_LOG_STDERR); + * @endcode */ int clicon_log_init(char *ident, int upto, int flags) diff --git a/lib/src/clixon_options.c b/lib/src/clixon_options.c index 9ec65124..3cd3a799 100644 --- a/lib/src/clixon_options.c +++ b/lib/src/clixon_options.c @@ -212,14 +212,6 @@ clicon_option_sanity(clicon_hash_t *copt) clicon_err(OE_UNIX, 0, "CLICON_NETCONF_DIR not defined in config file"); goto done; } - if (!hash_lookup(copt, "CLICON_RUNNING_DB")){ - clicon_err(OE_UNIX, 0, "CLICON_RUNNING_DB not defined in config file"); - goto done; - } - if (!hash_lookup(copt, "CLICON_CANDIDATE_DB")){ - clicon_err(OE_UNIX, 0, "CLICON_CANDIDATE_DB not defined in config file"); - goto done; - } if (!hash_lookup(copt, "CLICON_YANG_DIR")){ clicon_err(OE_UNIX, 0, "CLICON_YANG_DIR not defined in config file"); goto done; @@ -404,20 +396,6 @@ clicon_yang_module_revision(clicon_handle h) return clicon_option_str(h, "CLICON_YANG_MODULE_REVISION"); } -/* candidate database: get name */ -char * -clicon_candidate_db(clicon_handle h) -{ - return clicon_option_str(h, "CLICON_CANDIDATE_DB"); -} - -/* running database: get name */ -char * -clicon_running_db(clicon_handle h) -{ - return clicon_option_str(h, "CLICON_RUNNING_DB"); -} - char * clicon_backend_dir(clicon_handle h) { @@ -472,14 +450,14 @@ clicon_sock_family(clicon_handle h) return AF_UNIX; /* default */ } -/* get information about socket: unix domain filepath, or addr:path */ +/*! Get information about socket: unix domain filepath, or addr:path */ char * clicon_sock(clicon_handle h) { return clicon_option_str(h, "CLICON_SOCK"); } -/* get port for backend socket in case of AF_INET or AF_INET6 */ +/*! Get port for backend socket in case of AF_INET or AF_INET6 */ int clicon_sock_port(clicon_handle h) { @@ -608,8 +586,43 @@ clicon_cli_genmodel_completion(clicon_handle h) return 0; } -/* - * Get dbspec (YANG variant) +/* Where are "running" and "candidate" databases? */ +char * +clicon_xmldb_dir(clicon_handle h) +{ + return clicon_option_str(h, "CLICON_XMLDB_DIR"); +} + +/*! Set if xmldb runs in a separate process (clixon_xmldb). */ +int +clicon_xmldb_rpc(clicon_handle h) +{ + char *s; + + if ((s = clicon_option_str(h, "CLICON_XMLDB_RPC")) == NULL) + return -1; + return atoi(s); +} + +/*! Get xmldb inet address */ +char * +clicon_xmldb_addr(clicon_handle h) +{ + return clicon_option_str(h, "CLICON_XMLDB_ADDR"); +} + +/*! Get port for xmldb address in case of AF_INET or AF_INET6 */ +uint16_t +clicon_xmldb_port(clicon_handle h) +{ + char *s; + + if ((s = clicon_option_str(h, "CLICON_XMLDB_PORT")) == NULL) + return -1; + return atoi(s); +} + +/*! Get YANG specification * Must use hash functions directly since they are not strings. */ yang_spec * diff --git a/lib/src/clixon_proto.c b/lib/src/clixon_proto.c index 4f6d78d0..5293dff3 100644 --- a/lib/src/clixon_proto.c +++ b/lib/src/clixon_proto.c @@ -72,11 +72,6 @@ static const struct map_type2str msgmap[] = { {CLICON_MSG_CHANGE, "change"}, {CLICON_MSG_SAVE, "save"}, {CLICON_MSG_LOAD, "load"}, - {CLICON_MSG_COPY, "copy"}, - {CLICON_MSG_RM, "rm"}, - {CLICON_MSG_INITDB, "initdb"}, - {CLICON_MSG_LOCK, "lock"}, - {CLICON_MSG_UNLOCK, "unlock"}, {CLICON_MSG_KILL, "kill"}, {CLICON_MSG_DEBUG, "debug"}, {CLICON_MSG_CALL, "call"}, @@ -193,7 +188,8 @@ msg_dump(struct clicon_msg *msg) } int -clicon_msg_send(int s, struct clicon_msg *msg) +clicon_msg_send(int s, + struct clicon_msg *msg) { int retval = -1; @@ -337,8 +333,8 @@ clicon_rpc_connect_inet(struct clicon_msg *msg, int *sock0, const char *label) { - int retval = -1; - int s = -1; + int retval = -1; + int s = -1; struct sockaddr_in addr; clicon_debug(1, "Send %s msg to %s:%hu", diff --git a/lib/src/clixon_proto_client.c b/lib/src/clixon_proto_client.c index 816a4948..8a4373fd 100644 --- a/lib/src/clixon_proto_client.c +++ b/lib/src/clixon_proto_client.c @@ -284,116 +284,6 @@ 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] filename1 src file - * @param[in] filename2 dst file - */ -int -clicon_rpc_copy(clicon_handle h, - char *filename1, - char *filename2) -{ - int retval = -1; - struct clicon_msg *msg; - - if ((msg=clicon_msg_copy_encode(filename1, filename2, - __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 request to remove a file from backend file system - * @param[in] h CLICON handle - * @param[in] filename File to remove - */ -int -clicon_rpc_rm(clicon_handle h, - char *filename) -{ - int retval = -1; - struct clicon_msg *msg; - - if ((msg=clicon_msg_rm_encode(filename, __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 database initialization request to backend server - * @param[in] h CLICON handle - * @param[in] db Name of database - */ -int -clicon_rpc_initdb(clicon_handle h, - char *db) -{ - int retval = -1; - struct clicon_msg *msg; - - if ((msg=clicon_msg_initdb_encode(db, __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 database lock request to backend server - * @param[in] h CLICON handle - * @param[in] db Name of database - */ -int -clicon_rpc_lock(clicon_handle h, - char *db) -{ - int retval = -1; - struct clicon_msg *msg; - - if ((msg=clicon_msg_lock_encode(db, __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 database unlock request to backend server - * @param[in] h CLICON handle - * @param[in] db Name of database - */ -int -clicon_rpc_unlock(clicon_handle h, - char *db) -{ - int retval = -1; - struct clicon_msg *msg; - - if ((msg=clicon_msg_unlock_encode(db, __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 409f7bfb..cc4ff8bb 100644 --- a/lib/src/clixon_proto_encode.c +++ b/lib/src/clixon_proto_encode.c @@ -58,52 +58,6 @@ #include "clixon_proto.h" #include "clixon_proto_encode.h" -/* Generic encode/decode functions for exactly one C-string (str) - */ -static struct clicon_msg * -clicon_msg_1str_encode(char *str, enum clicon_msg_type op, const char *label) -{ - struct clicon_msg *msg; - int hdrlen = sizeof(*msg); - uint16_t len; - int p; - - assert(str); - p = 0; - len = sizeof(*msg) + strlen(str) + 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(op); - msg->op_len = htons(len); - /* body */ - strncpy(msg->op_body+p, str, len-p-hdrlen); - p += strlen(str)+1; - return msg; -} - -static int -clicon_msg_1str_decode(struct clicon_msg *msg, - char **str, - const char *label) -{ - int p; - - p = 0; - /* body */ - if ((*str = chunk_sprintf(label, "%s", msg->op_body+p)) == NULL){ - clicon_err(OE_PROTO, errno, "%s: chunk_sprintf", - __FUNCTION__); - return -1; - } - p += strlen(*str)+1; - return 0; -} - - struct clicon_msg * clicon_msg_commit_encode(char *dbsrc, char *dbdst, uint32_t snapshot, uint32_t startup, @@ -544,141 +498,6 @@ clicon_msg_load_decode(struct clicon_msg *msg, return 0; } -struct clicon_msg * -clicon_msg_initdb_encode(char *filename, const char *label) -{ - clicon_debug(2, "%s: db: %s", __FUNCTION__, filename); - return clicon_msg_1str_encode(filename, CLICON_MSG_INITDB, label); -} - -int -clicon_msg_initdb_decode(struct clicon_msg *msg, - char **filename, - const char *label) -{ - int retval; - - retval = clicon_msg_1str_decode(msg, filename, label); - clicon_debug(2, "%s: db: %s", __FUNCTION__, *filename); - return retval; -} - -struct clicon_msg * -clicon_msg_rm_encode(char *filename, const char *label) -{ - clicon_debug(2, "%s: db: %s", __FUNCTION__, filename); - return clicon_msg_1str_encode(filename, CLICON_MSG_RM, label); -} - -int -clicon_msg_rm_decode(struct clicon_msg *msg, - char **filename, - const char *label) -{ - int retval; - - retval = clicon_msg_1str_decode(msg, filename, label); - clicon_debug(2, "%s: db: %s", __FUNCTION__, *filename); - return retval; -} - - -struct clicon_msg * -clicon_msg_copy_encode(char *filename_src, char *filename_dst, - const char *label) -{ - struct clicon_msg *msg; - int hdrlen = sizeof(*msg); - uint16_t len; - int p; - - clicon_debug(2, "%s: filename_src: %s filename_dst: %s", - __FUNCTION__, - filename_src, filename_dst); - p = 0; - len = hdrlen + strlen(filename_src) + 1 + strlen(filename_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, filename_src, len-p-hdrlen); - p += strlen(filename_src)+1; - strncpy(msg->op_body+p, filename_dst, len-p-hdrlen); - p += strlen(filename_dst)+1; - return msg; -} - -int -clicon_msg_copy_decode(struct clicon_msg *msg, - char **filename_src, char **filename_dst, - const char *label) -{ - int p; - - p = 0; - /* body */ - if ((*filename_src = chunk_sprintf(label, "%s", msg->op_body+p)) == NULL){ - clicon_err(OE_PROTO, errno, "%s: chunk_sprintf", - __FUNCTION__); - return -1; - } - p += strlen(*filename_src)+1; - - if ((*filename_dst = chunk_sprintf(label, "%s", msg->op_body+p)) == NULL){ - clicon_err(OE_PROTO, errno, "%s: chunk_sprintf", - __FUNCTION__); - return -1; - } - p += strlen(*filename_dst)+1; - clicon_debug(2, "%s: filename_src: %s filename_dst: %s", - __FUNCTION__, - *filename_src, *filename_dst); - return 0; -} - -struct clicon_msg * -clicon_msg_lock_encode(char *db, const char *label) -{ - clicon_debug(2, "%s: db: %s", __FUNCTION__, db); - return clicon_msg_1str_encode(db, CLICON_MSG_LOCK, label); -} - -int -clicon_msg_lock_decode(struct clicon_msg *msg, - char **db, - const char *label) -{ - int retval; - - retval = clicon_msg_1str_decode(msg, db, label); - clicon_debug(2, "%s: db: %s", __FUNCTION__, *db); - return retval; -} - -struct clicon_msg * -clicon_msg_unlock_encode(char *db, const char *label) -{ - clicon_debug(2, "%s: db: %s", __FUNCTION__, db); - return clicon_msg_1str_encode(db, CLICON_MSG_UNLOCK, label); -} - -int -clicon_msg_unlock_decode(struct clicon_msg *msg, - char **db, - const char *label) -{ - int retval; - - retval = clicon_msg_1str_decode(msg, db, label); - clicon_debug(2, "%s: db: %s", __FUNCTION__, *db); - return retval; -} - 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 9f01e9a6..4033a460 100644 --- a/lib/src/clixon_qdb.c +++ b/lib/src/clixon_qdb.c @@ -18,6 +18,25 @@ along with CLIXON; see the file LICENSE. If not, see . + * @note Some unclarities with locking. man dpopen defines the following flags + * with dpopen: + * `DP_ONOLCK', which means it opens a database file without + * file locking, + * `DP_OLCKNB', which means locking is performed without blocking. + * + * While connecting as a writer, an exclusive lock is invoked to + * the database file. While connecting as a reader, a shared lock is + * invoked to the database file. The thread blocks until the lock is + * achieved. If `DP_ONOLCK' is used, the application is responsible + * for exclusion control. + * The code below uses for + * write, delete: DP_OLCKNB + * read: DP_OLCKNB + * This means that a write fails if one or many reads are occurring, and + * a read or write fails if a write is occurring, and + * QDBM allows a single write _or_ multiple readers, but + * not both. This is obviously extremely limiting. + * NOTE, the locking in netconf and xmldb is a write lock. */ #ifdef HAVE_CONFIG_H @@ -33,10 +52,10 @@ #include #include #include +#include #include #include -#if defined(HAVE_DEPOT_H) || defined(HAVE_QDBM_DEPOT_H) #ifdef HAVE_DEPOT_H #include /* qdb api */ #else /* HAVE_QDBM_DEPOT_H */ @@ -57,7 +76,8 @@ * @param[in] omode see man dpopen */ static int -db_init_mode(char *file, int omode) +db_init_mode(char *file, + int omode) { DEPOT *dp; @@ -85,6 +105,16 @@ db_init(char *file) return db_init_mode(file, DP_OWRITER | DP_OCREAT ); /* DP_OTRUNC? */ } +int +db_delete(char *file) +{ + if (unlink(file) < 0){ + clicon_err(OE_DB, errno, "unlink %s", file); + return -1; + } + return 0; +} + /*! Write data to database * @param[in] file database file * @param[in] key database key @@ -99,7 +129,7 @@ db_set(char *file, char *key, void *data, size_t datalen) DEPOT *dp; /* Open database for writing */ - if ((dp = dpopen(file, DP_OWRITER | DP_OLCKNB, 0)) == NULL){ + if ((dp = dpopen(file, DP_OWRITER|DP_OLCKNB , 0)) == NULL){ clicon_err(OE_DB, 0, "db_set: dpopen(%s): %s", file, dperrmsg(dpecode)); @@ -263,7 +293,6 @@ db_del(char *file, char *key) return retval; } - /*! Check if entry in database exists * @param[in] file database file * @param[in] key database key @@ -457,6 +486,78 @@ db_sanitize(char *rx, const char *label) return NULL; } +#if 0 /* Test program */ +/* + * Turn this on to get an xpath test program + * Usage: clicon_xpath [] + * read xml from input + * Example compile: + gcc -g -o qdb -I. -I../clixon ./clixon_qdb.c -lclixon -lcligen -lqdbm +*/ + +static int +usage(char *argv0) +{ + fprintf(stderr, "usage:\n"); + fprintf(stderr, "\t%s init \n", argv0); + fprintf(stderr, "\t%s read \n", argv0); + fprintf(stderr, "\t%s write \n", argv0); + fprintf(stderr, "\t%s openread \n", argv0); + fprintf(stderr, "\t%s openwrite \n", argv0); + exit(0); +} + +int +main(int argc, char **argv) +{ + char *verb; + char *filename; + char *key; + char *val; + size_t len; + DEPOT *dp; + + if (argc < 3) + usage(argv[0]); + clicon_log_init(__FILE__, LOG_INFO, CLICON_LOG_STDERR); + verb = argv[1]; + filename = argv[2]; + if (strcmp(verb, "init")==0){ + db_init(filename); + } + else if (strcmp(verb, "read")==0){ + if (argc < 4) + usage(argv[0]); + key = argv[3]; + db_get_alloc(filename, key, (void**)&val, &len); + fprintf(stdout, "%s\n", val); + } + else if (strcmp(verb, "write")==0){ + if (argc < 5) + usage(argv[0]); + key = argv[3]; + val = argv[4]; + db_set(filename, key, val, strlen(val)+1); + } + else if (strcmp(verb, "openread")==0){ + if ((dp = dpopen(filename, DP_OREADER | DP_OLCKNB, 0)) == NULL){ + clicon_err(OE_DB, dpecode, "dbopen: %s", + dperrmsg(dpecode)); + return -1; + } + sleep(1000000); + } + else if (strcmp(verb, "openwrite")==0){ + if ((dp = dpopen(filename, DP_OWRITER | DP_OLCKNB, 0)) == NULL){ + clicon_err(OE_DB, dpecode, "dbopen: %s", + dperrmsg(dpecode)); + return -1; + } + sleep(1000000); + } + return 0; +} + +#endif /* Test program */ -#endif /* DEPOT */ diff --git a/lib/src/clixon_qdb.h b/lib/src/clixon_qdb.h index 135e8ca9..2656aff0 100644 --- a/lib/src/clixon_qdb.h +++ b/lib/src/clixon_qdb.h @@ -40,6 +40,8 @@ struct db_pair { */ int db_init(char *file); +int db_delete(char *file); + int db_set(char *file, char *key, void *data, size_t datalen); int db_get(char *file, char *key, void *data, size_t *datalen); diff --git a/lib/src/clixon_string.c b/lib/src/clixon_string.c index e038f929..a4b329fd 100644 --- a/lib/src/clixon_string.c +++ b/lib/src/clixon_string.c @@ -45,19 +45,23 @@ * The given string is split into a vector where the delimiter can be * any of the characters in the specified delimiter string. * - * See also clicon_strsplit() which is similar by operates on a full string - * delimiter rather than individual character delimiters. - * * The vector returned is one single memory chunk that must be unchunked * by the caller * - * @param string String to be split - * @param delim String of delimiter characters - * @param nvec Number of entries in returned vector - * @param label Chunk label for returned vector + * @param[in] string String to be split + * @param[in] delim String of delimiter characters + * @param[out] nvec Number of entries in returned vector + * @param[in] label Chunk label for returned vector + * @retval vec Vector of strings. Free with unchunk + * @retval NULL Error + * @see clicon_strsplit Operates on full string delimiters rather than + * individual character delimiters. */ char ** -clicon_sepsplit (char *string, char *delim, int *nvec, const char *label) +clicon_sepsplit (char *string, + char *delim, + int *nvec, + const char *label) { int idx; size_t siz; @@ -94,19 +98,25 @@ clicon_sepsplit (char *string, char *delim, int *nvec, const char *label) * the full delimiter string. The matched delimiters are not part of the * resulting vector. * - * See also clicon_sepsplit() which is similar by operates on individual - * character delimiters rather then a full string delimiter. + * See also clicon_sepsplit() which is similar * * The vector returned is one single memory chunk that must be unchunked * by the caller * - * @param string String to be split - * @param delim String of delimiter characters - * @param nvec Number of entries in returned vector - * @param label Chunk label for returned vector + * @param[in] string String to be split + * @param[in] delim String of delimiter characters + * @param[out] nvec Number of entries in returned vector + * @param[in] label Chunk label for returned vector + * @retval vec Vector of strings. Free with unchunk + * @retval NULL Error + * @see clicon_sepsplit Operates on individual character delimiters rather + * than full string delimiter. */ char ** -clicon_strsplit (char *string, char *delim, int *nvec, const char *label) +clicon_strsplit (char *string, + char *delim, + int *nvec, + const char *label) { int idx; size_t siz; @@ -142,15 +152,18 @@ clicon_strsplit (char *string, char *delim, int *nvec, const char *label) return vec; } - -/* - * Concatenate elements of a string array into a string. An optiona delimiter - * string can be specified which will be inserted betwen each element. - * Resulting string is chunk:ed using the specified group label and need to be - * unchunked by the caller +/*! Concatenate elements of a string array into a string. + * An optional delimiter string can be specified which will be inserted betwen + * each element. + * @param[in] label Chunk label for returned vector + * @retval str Joined string. Free with unchunk() + * @retval NULL Failure */ char * -clicon_strjoin (int argc, char **argv, char *delim, const char *label) +clicon_strjoin (int argc, + char **argv, + char *delim, + const char *label) { int i; int len; @@ -176,12 +189,15 @@ clicon_strjoin (int argc, char **argv, char *delim, const char *label) return str; } -/* - * Trim of whitespace in beginning and end of string. - * A new string is returned, chunked with specified label +/*! Trim whitespace in beginning and end of string. + * + * @param[in] label Chunk label for returned vector + * @retval str Trimmed string. Free with unchunk() + * @retval NULL Failure */ char * -clicon_strtrim(char *str, const char *label) +clicon_strtrim(char *str, + const char *label) { char *start, *end, *new; @@ -200,15 +216,18 @@ clicon_strtrim(char *str, const char *label) return new; } -/* - * clicon_sep - * given a string s, on format: a[b], separate it into two parts: a and b +/*! Given a string s, on format: a[b], separate it into two parts: a and b * [] are separators. * alterative use: * a/b -> a and b (where sep = "/") + * @param[in] label Chunk label for returned vector */ int -clicon_sep(char *s, const char sep[2], const char *label, char**a0, char **b0) +clicon_sep(char *s, + const char sep[2], + const char *label, + char **a0, + char **b0) { char *a = NULL; char *b = NULL; @@ -246,12 +265,12 @@ clicon_sep(char *s, const char sep[2], const char *label, char**a0, char **b0) } -/* - * strndup() for systems without it, such as xBSD +/*! strndup() for systems without it, such as xBSD */ #ifndef HAVE_STRNDUP char * -clicon_strndup (const char *str, size_t len) +clicon_strndup (const char *str, + size_t len) { char *new; size_t slen; @@ -270,16 +289,19 @@ clicon_strndup (const char *str, size_t len) } #endif /* ! HAVE_STRNDUP */ -/* - * clicon_strmatch - Match string against regexp. +/*! Match string against regexp. * - * Returns -1 on failure, 0 on no matach or >0 (length of matching substring) - * in case of a match. If a match pointer is given, the matching substring + * If a match pointer is given, the matching substring * will be allocated 'match' will be pointing to it. The match string must * be free:ed by the application. + * @retval -1 Failure + * @retval 0 No match + * @retval >0 Match: Length of matching substring */ int -clicon_strmatch(const char *str, const char *regexp, char **match) +clicon_strmatch(const char *str, + const char *regexp, + char **match) { size_t len; int status; @@ -316,12 +338,14 @@ clicon_strmatch(const char *str, const char *regexp, char **match) return len; } -/* - * clicon_strsub - substitute pattern in string. - * Returns new malloc:ed string on success or NULL on failure. +/*! Substitute pattern in string. + * @retval str Malloc:ed string on success, use free to deallocate + * @retval NULL Failure. */ char * -clicon_strsub(char *str, char *from, char *to) +clicon_strsub(char *str, + char *from, + char *to) { char **vec; int nvec; diff --git a/lib/src/clixon_xml.c b/lib/src/clixon_xml.c index 5acd904a..a6fc54ca 100644 --- a/lib/src/clixon_xml.c +++ b/lib/src/clixon_xml.c @@ -588,7 +588,9 @@ xml_find_body(cxobj *xn, char *name) * (otherwise it will not) */ int -xml_prune(cxobj *xparent, cxobj *xchild, int purge) +xml_prune(cxobj *xparent, + cxobj *xchild, + int purge) { int i; cxobj *xc = NULL; @@ -648,10 +650,13 @@ xml_free(cxobj *x) * @param[in] xn clicon xml tree * @param[in] level how many spaces to insert before each line * @param[in] prettyprint insert \n and spaces tomake the xml more readable. - * See also clicon_xml2cbuf + * @see clicon_xml2cbuf */ int -clicon_xml2file(FILE *f, cxobj *xn, int level, int prettyprint) +clicon_xml2file(FILE *f, + cxobj *xn, + int level, + int prettyprint) { cbuf *cb; int retval = -1; @@ -689,7 +694,10 @@ clicon_xml2file(FILE *f, cxobj *xn, int level, int prettyprint) * See also clicon_xml2file */ int -clicon_xml2cbuf(cbuf *cb, cxobj *cx, int level, int prettyprint) +clicon_xml2cbuf(cbuf *cb, + cxobj *cx, + int level, + int prettyprint) { cxobj *xc; @@ -797,7 +805,9 @@ FSM(char *tag, char ch, int state) * May block */ int -clicon_xml_parse_file(int fd, cxobj **cx, char *endtag) +clicon_xml_parse_file(int fd, + cxobj **cx, + char *endtag) { int len = 0; char ch; @@ -869,7 +879,8 @@ clicon_xml_parse_file(int fd, cxobj **cx, char *endtag) * cxobj *cx = NULL; * str = strdup(...); * str0 = str; - * clicon_xml_parse_string(&str0, &cx) + * if (clicon_xml_parse_string(&str0, &cx) < 0) + * err; * free(str0); * xml_free(cx); * @endcode diff --git a/lib/src/clixon_xml_db.c b/lib/src/clixon_xml_db.c index ecb276f5..bc2e5a86 100644 --- a/lib/src/clixon_xml_db.c +++ b/lib/src/clixon_xml_db.c @@ -20,7 +20,6 @@ * XML database * TODO: xmldb_del: or dbxml_put_xkey delete - * TODO: xmldb_get: xpath: only load partial tree */ #ifdef HAVE_CONFIG_H #include "clixon_config.h" /* generated by config & autoconf */ @@ -34,6 +33,9 @@ #include #include #include +#include +#include +#include #include #include @@ -43,6 +45,7 @@ /* clicon */ #include "clixon_err.h" #include "clixon_log.h" +#include "clixon_file.h" #include "clixon_queue.h" #include "clixon_string.h" #include "clixon_chunk.h" @@ -52,8 +55,10 @@ #include "clixon_yang.h" #include "clixon_handle.h" #include "clixon_xml.h" +#include "clixon_options.h" #include "clixon_xsl.h" #include "clixon_xml_parse.h" +#include "clixon_xml_db_rpc.h" #include "clixon_xml_db.h" /* @@ -331,7 +336,95 @@ xmlkeyfmt2xpath(char *xkfmt, return retval; } +/*! Database locking for candidate and running non-persistent + * Store an integer for running and candidate containing + * the session-id of the client holding the lock. + */ +static int _running_locked = 0; +static int _candidate_locked = 0; +/*! Lock database + */ +static int +db_lock(char *db, + int pid) +{ + if (strcmp("running", db) == 0) + _running_locked = pid; + else if (strcmp("candidate", db) == 0) + _candidate_locked = pid; + clicon_debug(1, "%s: locked by %u", db, pid); + return 0; +} + +/*! Unlock database + */ +static int +db_unlock(char *db) +{ + if (strcmp("running", db) == 0) + _running_locked = 0; + else if (strcmp("candidate", db) == 0) + _candidate_locked = 0; + return 0; +} + +/*! returns id of locker + * @retval 0 Not locked + * @retval >0 Id of locker + */ +static int +db_islocked(char *db) +{ + if (strcmp("running", db) == 0) + return (_running_locked); + else if (strcmp("candidate", db) == 0) + return(_candidate_locked); + return 0; +} + +/*! Translate from symbolic database name to actual filename in file-system + * @param[in] h Clicon handle + * @param[in] db Symbolic database name, eg "candidate", "running" + * @param[out] filename Filename. Unallocate after use with free() + * @retval 0 OK + * @retval -1 Error + * The filename reside in CLICON_XMLDB_DIR option + */ +static int +db2file(clicon_handle h, + char *db, + char **filename) +{ + int retval = -1; + cbuf *cb; + char *dir; + + if ((cb = cbuf_new()) == NULL){ + clicon_err(OE_XML, errno, "cbuf_new"); + goto done; + } + if ((dir = clicon_xmldb_dir(h)) == NULL){ + clicon_err(OE_XML, errno, "CLICON_XMLDB_DIR not set"); + goto done; + } + if (strcmp(db, "running") != 0 && + strcmp(db, "candidate") != 0 && + strcmp(db, "tmp") != 0){ + clicon_err(OE_XML, 0, "Unexpected database: %s", db); + goto done; + } + cprintf(cb, "%s/%s_db", dir, db); + if ((*filename = strdup(cbuf_get(cb))) == NULL){ + clicon_err(OE_UNIX, errno, "strdup"); + goto done; + } + retval = 0; + done: + if (cb) + cbuf_free(cb); + return retval; +} /*! Help function to append key values from an xml list to a cbuf * Example, a yang node x with keys a and b results in "x/a/b" @@ -415,7 +508,6 @@ create_keyvalues(cxobj *x, return retval; } - /*! Prune everything that has not been marked * @param[in] xt XML tree with some node marked * @param[out] upmark Set if a child (recursively) has marked set. @@ -672,22 +764,16 @@ xml_default(cxobj *x, * @param[in] dbname Name of database to search in (filename including dir path * @param[in] xpath String with XPATH syntax (or NULL for all) * @param[in] yspec Yang specification + * @param[in] vector If set, return list of results in xvec * @param[out] xtop XML tree. Freed by xml_free() * @retval 0 OK * @retval -1 Error - * @code - * cxobj *xt; - * yang_spec *yspec = clicon_dbspec_yang(h); - * if (xmldb_get(dbname, "/interfaces/interface[name="eth*"]", yspec, &xt) < 0) - * err; - * xml_free(xt); - * @endcode */ -int -xmldb_get(char *dbname, - char *xpath, - yang_spec *yspec, - cxobj **xtop) +static int +xmldb_get_tree(char *dbname, + char *xpath, + yang_spec *yspec, + cxobj **xtop) { int retval = -1; int i; @@ -780,7 +866,7 @@ xmldb_get(char *dbname, * @see xpath_vec * @see xmldb_get */ -int +static int xmldb_get_vec(char *dbname, char *xpath, yang_spec *yspec, @@ -803,6 +889,7 @@ xmldb_get_vec(char *dbname, for (i = 0; i < npairs; i++) fprintf(stderr, "%s %s\n", pairs[i].dp_key, pairs[i].dp_val?pairs[i].dp_val:""); + /* Read in whole tree */ for (i = 0; i < npairs; i++) { if (get(dbname, yspec, @@ -827,7 +914,86 @@ xmldb_get_vec(char *dbname, return retval; } +/*! Local variant of xmldb_get */ +static int +xmldb_get_local(clicon_handle h, + char *db, + char *xpath, + int vector, + cxobj **xtop, + cxobj ***xvec, + size_t *xlen) +{ + int retval = -1; + yang_spec *yspec; + char *dbname = NULL; + if (db2file(h, db, &dbname) < 0) + goto done; + if (dbname==NULL){ + clicon_err(OE_XML, 0, "dbname NULL"); + goto done; + } + yspec = clicon_dbspec_yang(h); + if (vector){ + if (xmldb_get_vec(dbname, xpath, yspec, xtop, xvec, xlen) < 0) + goto done; + } + else + if (xmldb_get_tree(dbname, xpath, yspec, xtop) < 0) + goto done; + retval = 0; + done: + if (dbname) + free(dbname); + return retval; + +} + +/*! Get content of database using xpath. + * The function returns a minimal tree that includes all sub-trees that match + * xpath. + * @param[in] h Clicon handle + * @param[in] db running | candidate + * @param[in] xpath String with XPATH syntax (or NULL for all) + * @param[in] vector If set, return list of results in xvec, else single tree. + * @param[out] xtop XML tree. Freed by xml_free() + * @param[out] xvec Vector of xml trees. Free after use + * @param[out] xlen Length of vector. + * @retval 0 OK + * @retval -1 Error + * @code + * cxobj *xt; + * cxobj **xvec; + * size_t xlen; + * yang_spec *yspec = clicon_dbspec_yang(h); + * if (xmldb_get(dbname, "/interfaces/interface[name="eth"]", yspec, + * 1, &xt, &xvec, &xlen) < 0) + * err; + * for (i=0; iys_keyword == Y_LEAF || y->ys_keyword == Y_LEAF_LIST){ - if (db_set(dbname, xk, val, strlen(val)+1) < 0) + if (db_set(filename, xk, val, strlen(val)+1) < 0) goto done; } else - if (db_set(dbname, xk, NULL, 0) < 0) + if (db_set(filename, xk, NULL, 0) < 0) goto done; break; case OP_DELETE: - if ((exists = db_exists(dbname, xk)) < 0) + if ((exists = db_exists(filename, xk)) < 0) goto done; if (exists == 0){ clicon_err(OE_DB, 0, "OP_DELETE: %s does not exists in database", xk); @@ -1152,10 +1332,10 @@ xmldb_put_xkey(char *dbname, if ((crx = cbuf_new()) == NULL) goto done; cprintf(crx, "^%s.*$", xk); - if ((npairs = db_regexp(dbname, cbuf_get(crx), __FUNCTION__, &pairs, 0)) < 0) + if ((npairs = db_regexp(filename, cbuf_get(crx), __FUNCTION__, &pairs, 0)) < 0) goto done; for (i = 0; i < npairs; i++) { - if (db_del(dbname, pairs[i].dp_key) < 0) + if (db_del(filename, pairs[i].dp_key) < 0) goto done; } break; @@ -1164,6 +1344,8 @@ xmldb_put_xkey(char *dbname, } retval = 0; done: + if (filename) + free(filename); if (ckey) cbuf_free(ckey); if (csubkey) @@ -1174,17 +1356,45 @@ xmldb_put_xkey(char *dbname, return retval; } -/*! Raw dump of database, just keys and values, no xml interpretation - * param[in] f File - * param[in] dbname Name of database - * param[in] rxkey Key regexp, eg "^.*$" + +/*! Modify database provided an XML database key and an operation + * @param[in] dbname Name of database to search in (filename including dir path) + * @param[in] xk XML Key, eg /aa/bb/17/name + * @param[in] val Key value, eg "17" + * @param[in] yspec Yang specification + * @param[in] op OP_MERGE, OP_REPLACE, OP_REMOVE, etc + * @retval 0 OK + * @retval -1 Error + * @code + * if (xmldb_put_xkey(h, db, "/aa/bb/17/name", "17", OP_MERGE) < 0) + * err; + * @endcode */ int -xmldb_dump(FILE *f, - char *dbname, - char *rxkey) +xmldb_put_xkey(clicon_handle h, + char *db, + char *xk, + char *val, + enum operation_type op) { - int retval = 0; + if (clicon_xmldb_rpc(h)) + return xmldb_put_xkey_rpc(h, db, xk, val, op); + else + return xmldb_put_xkey_local(h, db, xk, val, op); +} + +/*! Raw dump of database, just keys and values, no xml interpretation + * @param[in] f File + * @param[in] dbfile File-name of database. This is a local file + * @param[in] rxkey Key regexp, eg "^.*$" + * @note This function can only be called locally. + */ +int +xmldb_dump(FILE *f, + char *dbfilename, + char *rxkey) +{ + int retval = -1; int npairs; struct db_pair *pairs; @@ -1193,29 +1403,270 @@ xmldb_dump(FILE *f, rxkey = "^.*$"; /* Get all keys/values for vector */ - if ((npairs = db_regexp(dbname, rxkey, __FUNCTION__, &pairs, 0)) < 0) - return -1; + if ((npairs = db_regexp(dbfilename, rxkey, __FUNCTION__, &pairs, 0)) < 0) + goto done; for (npairs--; npairs >= 0; npairs--) fprintf(f, "%s %s\n", pairs[npairs].dp_key, pairs[npairs].dp_val?pairs[npairs].dp_val:""); + retval = 0; + done: unchunk_group(__FUNCTION__); return retval; } -int -xmldb_init(char *file) +/*! Local variant of xmldb_copy */ +static int +xmldb_copy_local(clicon_handle h, + char *from, + char *to) { - return db_init(file); + int retval = -1; + char *fromfile = NULL; + char *tofile = NULL; + + /* XXX lock */ + if (db2file(h, from, &fromfile) < 0) + goto done; + if (db2file(h, to, &tofile) < 0) + goto done; + if (clicon_file_copy(fromfile, tofile) < 0) + goto done; + retval = 0; + done: + if (fromfile) + free(fromfile); + if (tofile) + free(tofile); + return retval; } -#if 1 /* Test program */ +/*! Copy database + * @param[in] h Clicon handle + * @param[in] from Source database copy + * @param[in] to Destination database + * @retval -1 Error + * @retval 0 OK + */ +int +xmldb_copy(clicon_handle h, + char *from, + char *to) +{ + if (clicon_xmldb_rpc(h)) + return xmldb_copy_rpc(h, from, to); + else + return xmldb_copy_local(h, from, to); +} + +/* Local variant of xmldb_lock */ +static int +xmldb_lock_local(clicon_handle h, + char *db, + int pid) +{ + int retval = -1; + + if (db_islocked(db)){ + if (pid != db_islocked(db)){ + clicon_err(OE_DB, 0, "lock failed: locked by %d", db_islocked(db)); + goto done; + } + } + else + db_lock(db, pid); + retval = 0; + done: + return retval; +} + +/*! Lock database + * @param[in] h Clicon handle + * @param[in] db Database + * @param[in] pid Process id + * @retval -1 Error + * @retval 0 OK + */ +int +xmldb_lock(clicon_handle h, + char *db, + int pid) +{ + if (clicon_xmldb_rpc(h)) + return xmldb_lock_rpc(h, db, pid); + else + return xmldb_lock_local(h, db, pid); +} + +/*! Local variant of xmldb_unlock */ +static int +xmldb_unlock_local(clicon_handle h, + char *db, + int pid) +{ + int retval = -1; + int pid1; + + pid1 = db_islocked(db); + if (pid1){ + if (pid == pid1) + db_unlock(db); + else{ + clicon_err(OE_DB, 0, "unlock failed: locked by %d", pid1); + goto done; + } + } + retval = 0; + done: + return retval; +} + +/*! Unlock database + * @param[in] h Clicon handle + * @param[in] db Database + * @param[in] pid Process id + * @retval -1 Error + * @retval 0 OK + */ +int +xmldb_unlock(clicon_handle h, + char *db, + int pid) +{ + if (clicon_xmldb_rpc(h)) + return xmldb_unlock_rpc(h, db, pid); + else + return xmldb_unlock_local(h, db, pid); +} + +/*! Local variant of xmldb_islocked */ +static int +xmldb_islocked_local(clicon_handle h, + char *db) +{ + return db_islocked(db); +} + +/*! Check if database is locked + * @param[in] h Clicon handle + * @param[in] db Database + * @retval -1 Error + * @retval 0 Not locked + * @retval >0 Id of locker + */ +int +xmldb_islocked(clicon_handle h, + char *db) +{ + if (clicon_xmldb_rpc(h)) + return xmldb_islocked_rpc(h, db); + else + return xmldb_islocked_local(h, db); +} + +/*! Local variant of xmldb_exists */ +static int +xmldb_exists_local(clicon_handle h, + char *db) +{ + int retval = -1; + char *filename = NULL; + struct stat sb; + + if (db2file(h, db, &filename) < 0) + goto done; + if (lstat(filename, &sb) < 0) + retval = 0; + else + retval = 1; + done: + if (filename) + free(filename); + return retval; +} + +/*! Check if db exists + * @retval -1 Error + * @retval 0 No it does not exist + * @retval 1 Yes it exists + */ +int +xmldb_exists(clicon_handle h, + char *db) +{ + if (clicon_xmldb_rpc(h)) + return xmldb_exists_rpc(h, db); + else + return xmldb_exists_local(h, db); +} + +/*! Local variant of xmldb_delete */ +static int +xmldb_delete_local(clicon_handle h, + char *db) +{ + int retval = -1; + char *filename = NULL; + + if (db2file(h, db, &filename) < 0) + goto done; + if (db_delete(filename) < 0) + goto done; + retval = 0; + done: + if (filename) + free(filename); + return retval; +} + +/*! Delete database. Remove file */ +int +xmldb_delete(clicon_handle h, + char *db) +{ + if (clicon_xmldb_rpc(h)) + return xmldb_delete_rpc(h, db); + else + return xmldb_delete_local(h, db); +} + +/*! Local variant of xmldb_init */ +static int +xmldb_init_local(clicon_handle h, + char *db) +{ + int retval = -1; + char *filename = NULL; + + if (db2file(h, db, &filename) < 0) + goto done; + if (db_init(filename) < 0) + goto done; + retval = 0; + done: + if (filename) + free(filename); + return retval; +} + +/*! Initialize database */ +int +xmldb_init(clicon_handle h, + char *db) +{ + if (clicon_xmldb_rpc(h)) + return xmldb_init_rpc(h, db); + else + return xmldb_init_local(h, db); +} + +#if 0 /* Test program */ /* * Turn this on to get an xpath test program * Usage: clicon_xpath [] * read xml from input * Example compile: - gcc -g -o xmldb -I. -I../clicon ./clicon_xmldb.c -lclicon -lcligen + gcc -g -o xmldb -I. -I../clixon ./clixon_xmldb.c -lclixon -lcligen */ static int @@ -1260,7 +1711,7 @@ main(int argc, char **argv) if (argc < 5) usage(argv[0]); xpath = argc>5?argv[5]:NULL; - if (xmldb_get(db, xpath, yspec, &xt) < 0) + if (xmldb_get(h, db, xpath, 0, &xt, NULL, NULL) < 0) goto done; clicon_xml2file(stdout, xt, 0, 1); } @@ -1283,7 +1734,7 @@ main(int argc, char **argv) op = OP_REMOVE; else usage(argv[0]); - if (xmldb_put(db, xn, yspec, op) < 0) + if (xmldb_put(h, db, xn, op) < 0) goto done; } else diff --git a/lib/src/clixon_xml_db_rpc.c b/lib/src/clixon_xml_db_rpc.c new file mode 100644 index 00000000..210f92aa --- /dev/null +++ b/lib/src/clixon_xml_db_rpc.c @@ -0,0 +1,570 @@ +/* + * + Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren + + This file is part of CLIXON. + + CLIXON is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + CLIXON is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with CLIXON; see the file LICENSE. If not, see + . + + * XML database + * TODO: xmldb_del: or dbxml_put_xkey delete + */ +#ifdef HAVE_CONFIG_H +#include "clixon_config.h" /* generated by config & autoconf */ +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* cligen */ +#include + +/* clicon */ +#include "clixon_err.h" +#include "clixon_log.h" +#include "clixon_queue.h" +#include "clixon_string.h" +#include "clixon_chunk.h" +#include "clixon_hash.h" +#include "clixon_handle.h" +#include "clixon_qdb.h" +#include "clixon_yang.h" +#include "clixon_handle.h" +#include "clixon_yang.h" +#include "clixon_options.h" +#include "clixon_xml.h" +#include "clixon_xsl.h" +#include "clixon_xml_parse.h" +#include "clixon_xml_db.h" +#include "clixon_xml_db_rpc.h" + +static int +xmldb_rpc(clicon_handle h, + char *data, + size_t len, + char *retdata, + size_t *retlen + ) +{ + int retval = -1; + char *dst; + uint16_t port; + int s = -1; + struct sockaddr_in addr; + + if ((dst = clicon_xmldb_addr(h)) == NULL){ + clicon_err(OE_CFG, errno, "CLICON_XMLDB_ADDR option not set"); + goto done; + } + if ((port = clicon_xmldb_port(h)) == 0){ + clicon_err(OE_CFG, errno, "CLICON_XMLDB_PORT option not set"); + goto done; + } + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + if (inet_pton(addr.sin_family, dst, &addr.sin_addr) != 1) + goto done; /* Could check getaddrinfo */ + if ((s = socket(addr.sin_family, SOCK_STREAM, 0)) < 0) { + clicon_err(OE_CFG, errno, "socket"); + return -1; + } + if (connect(s, (struct sockaddr*)&addr, sizeof(addr)) < 0){ + clicon_err(OE_CFG, errno, "connecting socket inet4"); + close(s); + goto done; + } + if (write(s, data, len) < 0){ + clicon_err(OE_UNIX, errno, "write"); + goto done; + } + if ((*retlen = read(s, retdata, *retlen)) < 0){ + clicon_err(OE_UNIX, errno, "write"); + goto done; + } + retval = 0; + if (debug > 1) + fprintf(stderr, "%s: \"%s\"\n", __FUNCTION__, retdata); + done: + if (s != -1) + close(s); + return retval; +} + +/*! Send put request to backend daemon + * @param[in] h CLICON handle + * @param[in] db running|candidate + * @retval 0 + */ +int +xmldb_put_rpc(clicon_handle h, + char *db, + cxobj *xt, + enum operation_type op) +{ + int retval = -1; + cbuf *cb = NULL; + char retbuf[BUFSIZ]; + char *rb = retbuf; + size_t retlen = sizeof(retbuf); + char *opstr; + + if ((cb = cbuf_new()) == NULL) + goto done; + cprintf(cb, ""); + cprintf(cb, "<%s/>", db); + if (op){ + switch (op){ + case OP_REPLACE: + opstr = "replace"; + break; + case OP_MERGE: + opstr = "merge"; + break; + case OP_NONE: + opstr = "none"; + break; + default: + break; + } + cprintf(cb, "%s", opstr); + } + cprintf(cb, ""); + if (clicon_xml2cbuf(cb, xt, 0, 1) < 0) + goto done; + cprintf(cb, ""); + cprintf(cb, "]]>]]>"); + if (xmldb_rpc(h, + cbuf_get(cb), + cbuf_len(cb)+1, + rb, &retlen) < 0) + goto done; + retval = 0; + done: + if (cb) + cbuf_free(cb); + return retval; +} + +/*! Send put xkey request to backend daemon + * @param[in] h CLICON handle + * @param[in] db running|candidate + * @retval 0 + */ +int +xmldb_put_xkey_rpc(clicon_handle h, + char *db, + char *xk, + char *val, + enum operation_type op) +{ + int retval = -1; + cbuf *cb = NULL; + char retbuf[BUFSIZ]; + char *rb = retbuf; + size_t retlen = sizeof(retbuf); + char *opstr; + + if ((cb = cbuf_new()) == NULL) + goto done; + cprintf(cb, ""); + cprintf(cb, "<%s/>", db); + if (op){ + switch (op){ + case OP_REPLACE: + opstr = "replace"; + break; + case OP_MERGE: + opstr = "merge"; + break; + case OP_NONE: + opstr = "none"; + break; + default: + break; + } + cprintf(cb, "%s", opstr); + } + cprintf(cb, "%s", xk); + cprintf(cb, "%s", val); + cprintf(cb, "]]>]]>"); + if (xmldb_rpc(h, + cbuf_get(cb), + cbuf_len(cb)+1, + rb, &retlen) < 0) + goto done; + retval = 0; + done: + if (cb) + cbuf_free(cb); + return retval; +} + +/*! Send get request to backend daemon + * @param[in] h CLICON handle + * @param[in] db running|candidate + * @retval 0 + */ +int +xmldb_get_rpc(clicon_handle h, + char *db, + char *xpath, + int vector, + cxobj **xtop, + cxobj ***xvec, + size_t *xlen) +{ + int retval = -1; + cbuf *cb = NULL; + char retbuf[BUFSIZ]; + char *rb = retbuf; + size_t retlen = sizeof(retbuf); + cxobj *xt=NULL; + cxobj *xc; + int i; + + if ((cb = cbuf_new()) == NULL) + goto done; + cprintf(cb, ""); + cprintf(cb, "<%s/>", db); + if (xpath) + cprintf(cb, "%s", xpath); + if (vector) + cprintf(cb, ""); + cprintf(cb, "]]>]]>"); + if (xmldb_rpc(h, + cbuf_get(cb), + cbuf_len(cb)+1, + rb, &retlen) < 0) + goto done; + if (clicon_xml_parse_string(&rb, &xt) < 0) + goto done; + if (vector){ + i=0; + if ((*xvec = calloc(xml_child_nr(xt), sizeof(cxobj*))) ==NULL){ + clicon_err(OE_UNIX, errno, "calloc"); + goto done; + } + xc = NULL; + while ((xc = xml_child_each(xt, xc, CX_ELMNT)) != NULL) { + (*xvec)[i++] = xc; + } + *xlen = i; + *xtop = xt; + xt = NULL; + } + else{ + if ((xc = xml_child_i(xt, 0)) != NULL){ + xml_prune(xt, xc, 0); /* kludge to remove top-level tag (eg top/clicon) */ + xml_parent_set(xc, NULL); + if (debug > 1) + clicon_xml2file(stderr, xc, 0, 1); + } + *xtop = xc; + } + + retval = 0; + done: + if (xt) + xml_free(xt); + if (cb) + cbuf_free(cb); + return retval; +} + +/*! Copy database + * @param[in] h Clicon handle + * @param[in] from Source database copy + * @param[in] to Destination database + * @retval -1 Error + * @retval 0 OK + */ +int +xmldb_copy_rpc(clicon_handle h, + char *from, + char *to) +{ + int retval = -1; + cbuf *cb = NULL; + char retbuf[BUFSIZ]; + char *rb = retbuf; + size_t retlen = sizeof(retbuf); + cxobj *xt = NULL; + + if ((cb = cbuf_new()) == NULL) + goto done; + cprintf(cb, ""); + cprintf(cb, "<%s/>", from); + cprintf(cb, "<%s/>", to); + cprintf(cb, "]]>]]>"); + if (xmldb_rpc(h, + cbuf_get(cb), + cbuf_len(cb)+1, + rb, &retlen) < 0) + goto done; + if (clicon_xml_parse_string(&rb, &xt) < 0) + goto done; + if (xpath_first(xt, "//ok")) + retval = 0; + done: + if (xt) + xml_free(xt); + if (cb) + cbuf_free(cb); + return retval; +} + +/*! Lock database + * @param[in] h Clicon handle + * @param[in] db Database + * @param[in] pid Process id + * @retval -1 Error + * @retval 0 OK + */ +int +xmldb_lock_rpc(clicon_handle h, + char *db, + int id) +{ + int retval = -1; + cbuf *cb = NULL; + char retbuf[BUFSIZ]; + char *rb = retbuf; + size_t retlen = sizeof(retbuf); + cxobj *xt = NULL; + + if ((cb = cbuf_new()) == NULL) + goto done; + cprintf(cb, ""); + cprintf(cb, "<%s/>", db); + cprintf(cb, "<%u/>", id); + cprintf(cb, "]]>]]>"); + if (xmldb_rpc(h, + cbuf_get(cb), + cbuf_len(cb)+1, + rb, &retlen) < 0) + goto done; + if (clicon_xml_parse_string(&rb, &xt) < 0) + goto done; + if (xpath_first(xt, "//ok")) + retval = 0; + done: + if (xt) + xml_free(xt); + if (cb) + cbuf_free(cb); + return retval; +} + +/*! Unlock database + * @param[in] h Clicon handle + * @param[in] db Database + * @param[in] pid Process id + * @retval -1 Error + * @retval 0 OK + */ +int +xmldb_unlock_rpc(clicon_handle h, + char *db, + int id) +{ + int retval = -1; + cbuf *cb = NULL; + char retbuf[BUFSIZ]; + char *rb = retbuf; + size_t retlen = sizeof(retbuf); + cxobj *xt = NULL; + + if ((cb = cbuf_new()) == NULL) + goto done; + cprintf(cb, ""); + cprintf(cb, "<%s/>", db); + cprintf(cb, "<%u/>", id); + cprintf(cb, "]]>]]>"); + if (xmldb_rpc(h, + cbuf_get(cb), + cbuf_len(cb)+1, + rb, &retlen) < 0) + goto done; + if (clicon_xml_parse_string(&rb, &xt) < 0) + goto done; + if (xpath_first(xt, "//ok")) + retval = 0; + done: + if (xt) + xml_free(xt); + if (cb) + cbuf_free(cb); + return retval; +} + +/*! Check if database is locked + * @param[in] h Clicon handle + * @param[in] db Database + * @retval -1 Error + * @retval pid Process id if locked + */ +int +xmldb_islocked_rpc(clicon_handle h, + char *db) +{ + int retval = -1; + cbuf *cb = NULL; + char retbuf[BUFSIZ]; + char *rb = retbuf; + size_t retlen = sizeof(retbuf); + cxobj *xt = NULL; + cxobj *x; + + if ((cb = cbuf_new()) == NULL) + goto done; + cprintf(cb, ""); + cprintf(cb, "<%s/>", db); + cprintf(cb, "]]>]]>"); + if (xmldb_rpc(h, + cbuf_get(cb), + cbuf_len(cb)+1, + rb, &retlen) < 0) + goto done; + if (clicon_xml_parse_string(&rb, &xt) < 0) + goto done; + if (xpath_first(xt, "//unlocked")) + retval = 0; + else + if ((x=xpath_first(xt, "//locked")) != NULL) + retval = atoi(xml_body(x)); + done: + if (xt) + xml_free(xt); + if (cb) + cbuf_free(cb); + return retval; +} + +/*! Send exists request to backend daemon + * @param[in] h CLICON handle + * @param[in] db running|candidate + * @retval -1 Error + * @retval 0 No it does not exist + * @retval 1 Yes it exists + */ +int +xmldb_exists_rpc(clicon_handle h, + char *db) +{ + int retval = -1; + cbuf *cb = NULL; + char retbuf[BUFSIZ]; + char *rb = retbuf; + size_t retlen = sizeof(retbuf); + cxobj *xt = NULL; + + if ((cb = cbuf_new()) == NULL) + goto done; + cprintf(cb, ""); + cprintf(cb, "<%s/>", db); + cprintf(cb, "]]>]]>"); + if (xmldb_rpc(h, + cbuf_get(cb), + cbuf_len(cb)+1, + rb, &retlen) < 0) + goto done; + if (clicon_xml_parse_string(&rb, &xt) < 0) + goto done; + if (xpath_first(xt, "//ok")) + retval = 1; + else + retval = 0; + done: + if (xt) + xml_free(xt); + if (cb) + cbuf_free(cb); + return retval; +} + + +/*! Send delete request to backend daemon + * @param[in] h CLICON handle + * @param[in] db running|candidate + * @retval 0 + */ +int +xmldb_delete_rpc(clicon_handle h, + char *db) +{ + int retval = -1; + cbuf *cb = NULL; + char retbuf[BUFSIZ]; + char *rb = retbuf; + size_t retlen = sizeof(retbuf); + + if ((cb = cbuf_new()) == NULL) + goto done; + cprintf(cb, ""); + cprintf(cb, "<%s/>", db); + cprintf(cb, "]]>]]>"); + if (xmldb_rpc(h, + cbuf_get(cb), + cbuf_len(cb)+1, + rb, &retlen) < 0) + goto done; + retval = 0; + done: + if (cb) + cbuf_free(cb); + return retval; +} + +/*! Send init request to backend daemon + * @param[in] h CLICON handle + * @param[in] db running|candidate + * @retval 0 + */ +int +xmldb_init_rpc(clicon_handle h, + char *db) +{ + int retval = -1; + cbuf *cb = NULL; + char retbuf[BUFSIZ]; + char *rb = retbuf; + size_t retlen = sizeof(retbuf); + + if ((cb = cbuf_new()) == NULL) + goto done; + cprintf(cb, ""); + cprintf(cb, "<%s/>", db); + cprintf(cb, "]]>]]>"); + if (xmldb_rpc(h, + cbuf_get(cb), + cbuf_len(cb)+1, + rb, &retlen) < 0) + goto done; + retval = 0; + done: + if (cb) + cbuf_free(cb); + return retval; +} diff --git a/lib/src/clixon_yang.c b/lib/src/clixon_yang.c index 8f610afb..4e9cfbb3 100644 --- a/lib/src/clixon_yang.c +++ b/lib/src/clixon_yang.c @@ -1910,7 +1910,6 @@ yang_config(yang_stmt *ys) * @param f file to print to (if one of print options are enabled) * @param printspec print database (YANG) specification as read from file */ - int yang_spec_main(clicon_handle h, FILE *f, diff --git a/test/README b/test/README new file mode 100644 index 00000000..0c34d561 --- /dev/null +++ b/test/README @@ -0,0 +1,8 @@ +Some test cases: +With and without xmldb_rpc: +set a list entry +set a nested entry +Completion +validate with missing mandatory variable +commit +delete all \ No newline at end of file diff --git a/test/all.sh b/test/all.sh new file mode 100755 index 00000000..98e3b2d0 --- /dev/null +++ b/test/all.sh @@ -0,0 +1,11 @@ +#!/bin/sh +for test in test*.sh; do + echo "Running $test" + ./$test + errcode=$? + if [ $errcode -ne 0 ]; then + echo "Error in $test errcode=$errcode" + exit $errcode + fi +done + diff --git a/test/lib.sh b/test/lib.sh new file mode 100755 index 00000000..8948dee8 --- /dev/null +++ b/test/lib.sh @@ -0,0 +1,32 @@ +#!/bin/sh + +testnr=0 +testnname= +clixon_cf=/usr/local/etc/routing.conf +# error and exit +err(){ + echo "Error in Test$testnr [$testname] $1" + exit $testnr +} + +# Increment test number and print a nice string +new(){ + testnr=`expr $testnr + 1` + testname=$1 + echo "Test$testnr [$1]" +# sleep 1 +} + +# clicon_cli tester. First arg is command and second is expected outcome +clifn(){ + cmd=$1 + expect=$2 + ret=`$cmd` + if [ $? -ne 0 ]; then + err + fi + if [ "$ret" != "$expect" ]; then + err "\nExpected:\t\"$expect\"\nGot:\t\"$ret\"" + fi +} + diff --git a/test/test1.sh b/test/test1.sh new file mode 100755 index 00000000..ff34347e --- /dev/null +++ b/test/test1.sh @@ -0,0 +1,32 @@ +#!/bin/sh + +# include err() and new() functions +. ./lib.sh + +# kill old backend (if any) +new "kill old backend" +sudo clixon_backend -zf $clixon_cf + +if [ $? -ne 0 ]; then + err +fi +new "start backend" +# start new backend +sudo clixon_backend -If $clixon_cf -x 0 +if [ $? -ne 0 ]; then + err +fi +new "cli configure" +clifn "clixon_cli -1f $clixon_cf set interfaces interface eth0" "" + +new "cli show configuration" +clifn "clixon_cli -1f $clixon_cf show conf cli" "interfaces interface name eth0 +interfaces interface enabled htrue" + +new "Kill backend" +# kill backend +sudo clixon_backend -zf $clixon_cf +if [ $? -ne 0 ]; then + err +fi +