Merge branch 'modules-state'
This commit is contained in:
commit
2394c6f46e
43 changed files with 1755 additions and 587 deletions
|
|
@ -74,6 +74,7 @@ APPSRC += backend_socket.c
|
|||
APPSRC += backend_client.c
|
||||
APPSRC += backend_commit.c
|
||||
APPSRC += backend_plugin.c
|
||||
APPSRC += backend_startup.c
|
||||
APPOBJ = $(APPSRC:.c=.o)
|
||||
|
||||
# Accessible from plugin
|
||||
|
|
|
|||
|
|
@ -64,8 +64,8 @@
|
|||
#include <clixon/clixon.h>
|
||||
|
||||
#include "clixon_backend_handle.h"
|
||||
#include "backend_commit.h"
|
||||
#include "backend_plugin.h"
|
||||
#include "backend_commit.h"
|
||||
#include "backend_client.h"
|
||||
#include "backend_handle.h"
|
||||
|
||||
|
|
@ -208,7 +208,7 @@ from_client_get_config(clicon_handle h,
|
|||
if ((xfilter = xml_find(xe, "filter")) != NULL)
|
||||
if ((xpath = xml_find_value(xfilter, "select"))==NULL)
|
||||
xpath="/";
|
||||
if (xmldb_get(h, db, xpath, 1, &xret) < 0){
|
||||
if (xmldb_get(h, db, xpath, 1, &xret, NULL) < 0){
|
||||
if (netconf_operation_failed(cbret, "application", "read registry")< 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
|
|
@ -335,7 +335,7 @@ client_statedata(clicon_handle h,
|
|||
if ((retval = client_get_streams(h, yspec, xpath, "ietf-restconf-monitoring", "restconf-state", xret)) != 0)
|
||||
goto done;
|
||||
if (clicon_option_bool(h, "CLICON_MODULE_LIBRARY_RFC7895"))
|
||||
if ((retval = yang_modules_state_get(h, yspec, xpath, xret)) != 0)
|
||||
if ((retval = yang_modules_state_get(h, yspec, xpath, 0, xret)) != 0)
|
||||
goto done;
|
||||
if ((retval = clixon_plugin_statedata(h, yspec, xpath, xret)) != 0)
|
||||
goto done;
|
||||
|
|
@ -391,7 +391,7 @@ from_client_get(clicon_handle h,
|
|||
if ((xpath = xml_find_value(xfilter, "select"))==NULL)
|
||||
xpath="/";
|
||||
/* Get config */
|
||||
if (xmldb_get(h, "running", xpath, 0, &xret) < 0){
|
||||
if (xmldb_get(h, "running", xpath, 0, &xret, NULL) < 0){
|
||||
if (netconf_operation_failed(cbret, "application", "read registry")< 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
|
|
|
|||
|
|
@ -140,7 +140,9 @@ generic_validate(yang_spec *yspec,
|
|||
goto done;
|
||||
}
|
||||
|
||||
/*! Common code of candidate_validate and candidate_commit
|
||||
/*! Validate a candidate db and comnpare to running
|
||||
* Get both source and dest datastore, validate target, compute diffs
|
||||
* and call application callback validations.
|
||||
* @param[in] h Clicon handle
|
||||
* @param[in] candidate The candidate database. The wanted backend state
|
||||
* @retval -1 Error - or validation failed (but cbret not set)
|
||||
|
|
@ -167,10 +169,10 @@ validate_common(clicon_handle h,
|
|||
}
|
||||
/* 2. Parse xml trees
|
||||
* This is the state we are going from */
|
||||
if (xmldb_get(h, "running", "/", 1, &td->td_src) < 0)
|
||||
if (xmldb_get(h, "running", "/", 1, &td->td_src, NULL) < 0)
|
||||
goto done;
|
||||
/* This is the state we are going to */
|
||||
if (xmldb_get(h, candidate, "/", 1, &td->td_target) < 0)
|
||||
if (xmldb_get(h, candidate, "/", 1, &td->td_target, NULL) < 0)
|
||||
goto done;
|
||||
|
||||
/* Validate the target state. It is not completely clear this should be done
|
||||
|
|
@ -244,6 +246,90 @@ validate_common(clicon_handle h,
|
|||
goto done;
|
||||
}
|
||||
|
||||
/*! Validate a candidate db and comnpare to running XXX Experimental
|
||||
* Get both source and dest datastore, validate target, compute diffs
|
||||
* and call application callback validations.
|
||||
* @param[in] h Clicon handle
|
||||
* @param[in] candidate The candidate database. The wanted backend state
|
||||
* @retval -1 Error - or validation failed (but cbret not set)
|
||||
* @retval 0 Validation failed (with cbret set)
|
||||
* @retval 1 Validation OK
|
||||
* @note Need to differentiate between error and validation fail
|
||||
* 1. Parse startup XML (or JSON)
|
||||
* 2. If syntax failure, call startup-cb(ERROR), copy failsafe db to
|
||||
* candidate and commit. Done
|
||||
* 3. Check yang module versions between backend and init config XML. (msdiff)
|
||||
* 4. Validate startup db. (valid)
|
||||
* 5. If valid fails, call startup-cb(Invalid, msdiff), keep startup in candidate and commit failsafe db. Done.
|
||||
* 6. Call startup-cb(OK, msdiff) and commit.
|
||||
*/
|
||||
int
|
||||
startup_validate(clicon_handle h,
|
||||
char *db,
|
||||
cbuf *cbret)
|
||||
{
|
||||
int retval = -1;
|
||||
yang_spec *yspec;
|
||||
int ret;
|
||||
cxobj *xms = NULL;
|
||||
transaction_data_t *td = NULL;
|
||||
|
||||
/* Handcraft a transition with only target and add trees */
|
||||
if ((td = transaction_new()) == NULL)
|
||||
goto done;
|
||||
/* 2. Parse xml trees
|
||||
* This is the state we are going to
|
||||
* Note: xmsdiff contains non-matching modules
|
||||
*/
|
||||
if (xmldb_get(h, db, "/", 1, &td->td_target, &xms) < 0)
|
||||
goto done;
|
||||
if (xms && clixon_plugin_upgrade(h, xms) < 0)
|
||||
goto done;
|
||||
|
||||
/* Handcraft transition with with only add tree */
|
||||
if (cxvec_append(td->td_target, &td->td_avec, &td->td_alen) < 0)
|
||||
goto done;
|
||||
|
||||
/* 4. Call plugin transaction start callbacks */
|
||||
if (plugin_transaction_begin(h, td) < 0)
|
||||
goto done;
|
||||
|
||||
if ((yspec = clicon_dbspec_yang(h)) == NULL){
|
||||
clicon_err(OE_YANG, 0, "Yang spec not set");
|
||||
goto done;
|
||||
}
|
||||
/* 5. Make generic validation on all new or changed data.
|
||||
Note this is only call that uses 3-values */
|
||||
if ((ret = generic_validate(yspec, td, cbret)) < 0)
|
||||
goto done;
|
||||
if (ret == 0)
|
||||
goto fail; /* STARTUP_INVALID */
|
||||
|
||||
/* 6. Call plugin transaction validate callbacks */
|
||||
if (plugin_transaction_validate(h, td) < 0)
|
||||
goto done;
|
||||
|
||||
/* 7. Call plugin transaction complete callbacks */
|
||||
if (plugin_transaction_complete(h, td) < 0)
|
||||
goto done;
|
||||
retval = 1;
|
||||
done:
|
||||
if (td)
|
||||
transaction_free(td);
|
||||
if (xms)
|
||||
xml_free(xms);
|
||||
return retval;
|
||||
fail: /* cbret should be set */
|
||||
if (cbuf_len(cbret)==0){
|
||||
clicon_err(OE_CFG, EINVAL, "Validation fail but cbret not set");
|
||||
goto done;
|
||||
}
|
||||
retval = 0;
|
||||
goto done;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*! Do a diff between candidate and running, then start a commit transaction
|
||||
*
|
||||
* The code reverts changes if the commit fails. But if the revert
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@
|
|||
int from_client_validate(clicon_handle h, char *db, cbuf *cbret);
|
||||
int from_client_commit(clicon_handle h, int pid, cbuf *cbret);
|
||||
int from_client_discard_changes(clicon_handle h, int pid, cbuf *cbret);
|
||||
int startup_validate(clicon_handle h, char *db, cbuf *cbret);
|
||||
int candidate_commit(clicon_handle h, char *db, cbuf *cbret);
|
||||
|
||||
#endif /* _BACKEND_COMMIT_H_ */
|
||||
|
|
|
|||
|
|
@ -68,9 +68,10 @@
|
|||
#include "clixon_backend_handle.h"
|
||||
#include "backend_socket.h"
|
||||
#include "backend_client.h"
|
||||
#include "backend_commit.h"
|
||||
#include "backend_plugin.h"
|
||||
#include "backend_commit.h"
|
||||
#include "backend_handle.h"
|
||||
#include "backend_startup.h"
|
||||
|
||||
/* Command line options to be passed to getopt(3) */
|
||||
#define BACKEND_OPTS "hD:f:l:d:p:b:Fza:u:P:1s:c:g:y:x:o:"
|
||||
|
|
@ -135,84 +136,6 @@ backend_sig_term(int arg)
|
|||
clicon_exit_set(); /* checked in event_loop() */
|
||||
}
|
||||
|
||||
/*! usage
|
||||
*/
|
||||
static void
|
||||
usage(clicon_handle h,
|
||||
char *argv0)
|
||||
{
|
||||
char *plgdir = clicon_backend_dir(h);
|
||||
char *confsock = clicon_sock(h);
|
||||
char *confpid = clicon_backend_pidfile(h);
|
||||
char *group = clicon_sock_group(h);
|
||||
|
||||
fprintf(stderr, "usage:%s <options>*\n"
|
||||
"where options are\n"
|
||||
"\t-h\t\tHelp\n"
|
||||
"\t-D <level>\tDebug level\n"
|
||||
"\t-f <file>\tCLICON config file\n"
|
||||
"\t-l (s|e|o|f<file>) Log on (s)yslog, std(e)rr or std(o)ut (stderr is default) Only valid if -F, if background syslog is on syslog.\n"
|
||||
"\t-d <dir>\tSpecify backend plugin directory (default: %s)\n"
|
||||
"\t-p <dir>\tYang directory path (see CLICON_YANG_DIR)\n"
|
||||
"\t-b <dir>\tSpecify XMLDB database directory\n"
|
||||
"\t-F\t\tRun in foreground, do not run as daemon\n"
|
||||
"\t-z\t\tKill other config daemon and exit\n"
|
||||
"\t-a UNIX|IPv4|IPv6 Internal backend socket family\n"
|
||||
"\t-u <path|addr>\tInternal socket domain path or IP addr (see -a)(default: %s)\n"
|
||||
"\t-P <file>\tPid filename (default: %s)\n"
|
||||
"\t-1\t\tRun once and then quit (dont wait for events)\n"
|
||||
"\t-s <mode>\tSpecify backend startup mode: none|startup|running|init)\n"
|
||||
"\t-c <file>\tLoad extra xml configuration, but don't commit.\n"
|
||||
"\t-g <group>\tClient membership required to this group (default: %s)\n"
|
||||
|
||||
"\t-y <file>\tLoad yang spec file (override yang main module)\n"
|
||||
"\t-x <plugin>\tXMLDB plugin\n"
|
||||
"\t-o \"<option>=<value>\"\tGive configuration option overriding config file (see clixon-config.yang)\n",
|
||||
argv0,
|
||||
plgdir ? plgdir : "none",
|
||||
confsock ? confsock : "none",
|
||||
confpid ? confpid : "none",
|
||||
group ? group : "none"
|
||||
);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
static int
|
||||
db_reset(clicon_handle h,
|
||||
char *db)
|
||||
{
|
||||
if (xmldb_exists(h, db) == 1 && xmldb_delete(h, db) != 0 && errno != ENOENT)
|
||||
return -1;
|
||||
if (xmldb_create(h, db) < 0)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! Merge db1 into db2 without commit
|
||||
* @retval -1 Error
|
||||
* @retval 0 Validation failed (with cbret set)
|
||||
* @retval 1 Validation OK
|
||||
*/
|
||||
static int
|
||||
db_merge(clicon_handle h,
|
||||
const char *db1,
|
||||
const char *db2,
|
||||
cbuf *cbret)
|
||||
{
|
||||
int retval = -1;
|
||||
cxobj *xt = NULL;
|
||||
|
||||
/* Get data as xml from db1 */
|
||||
if (xmldb_get(h, (char*)db1, NULL, 1, &xt) < 0)
|
||||
goto done;
|
||||
/* Merge xml into db2. Without commit */
|
||||
retval = xmldb_put(h, (char*)db2, OP_MERGE, xt, clicon_username_get(h), cbret);
|
||||
done:
|
||||
if (xt)
|
||||
xml_free(xt);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Create backend server socket and register callback
|
||||
* @param[in] h Clicon handle
|
||||
* @retval s Server socket file descriptor (see socket(2))
|
||||
|
|
@ -305,256 +228,88 @@ nacm_load_external(clicon_handle h)
|
|||
return retval;
|
||||
}
|
||||
|
||||
/*! Merge xml in filename into database
|
||||
* @retval -1 Error
|
||||
* @retval 0 Validation failed (with cbret set)
|
||||
* @retval 1 Validation OK
|
||||
*/
|
||||
static int
|
||||
load_extraxml(clicon_handle h,
|
||||
char *filename,
|
||||
const char *db,
|
||||
cbuf *cbret)
|
||||
{
|
||||
int retval = -1;
|
||||
cxobj *xt = NULL;
|
||||
int fd = -1;
|
||||
|
||||
if (filename == NULL)
|
||||
return 1;
|
||||
if ((fd = open(filename, O_RDONLY)) < 0){
|
||||
clicon_err(OE_UNIX, errno, "open(%s)", filename);
|
||||
goto done;
|
||||
}
|
||||
if (xml_parse_file(fd, "</config>", NULL, &xt) < 0)
|
||||
goto done;
|
||||
/* Replace parent w first child */
|
||||
if (xml_rootchild(xt, 0, &xt) < 0)
|
||||
goto done;
|
||||
/* Merge user reset state */
|
||||
retval = xmldb_put(h, (char*)db, OP_MERGE, xt, clicon_username_get(h), cbret);
|
||||
done:
|
||||
if (fd != -1)
|
||||
close(fd);
|
||||
if (xt)
|
||||
xml_free(xt);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Clixon none startup modes Do not touch running state
|
||||
*/
|
||||
static int
|
||||
startup_mode_none(clicon_handle h)
|
||||
{
|
||||
int retval = -1;
|
||||
|
||||
/* If it is not there, create candidate from running */
|
||||
if (xmldb_exists(h, "candidate") != 1)
|
||||
if (xmldb_copy(h, "running", "candidate") < 0)
|
||||
goto done;
|
||||
/* Load plugins and call plugin_init() */
|
||||
if (backend_plugin_initiate(h) != 0)
|
||||
goto done;
|
||||
retval = 0;
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Clixon init startup modes Start with a completely clean running state
|
||||
*/
|
||||
static int
|
||||
startup_mode_init(clicon_handle h)
|
||||
{
|
||||
int retval = -1;
|
||||
|
||||
/* Reset running, regardless */
|
||||
if (db_reset(h, "running") < 0)
|
||||
goto done;
|
||||
/* If it is not there, create candidate from running */
|
||||
if (xmldb_exists(h, "candidate") != 1)
|
||||
if (xmldb_copy(h, "running", "candidate") < 0)
|
||||
goto done;
|
||||
/* Load plugins and call plugin_init() */
|
||||
if (backend_plugin_initiate(h) != 0)
|
||||
goto done;
|
||||
retval = 0;
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Clixon running startup mode: Commit running db configuration into running
|
||||
/*! Given a retval, transform to status or fatal error
|
||||
*
|
||||
OK:
|
||||
copy reset commit merge
|
||||
running----+ |--------------------+--------+------>
|
||||
\ / /
|
||||
candidate +--------------------+ /
|
||||
/
|
||||
tmp |-------+-----+------------+---|
|
||||
reset extra file
|
||||
|
||||
COMMIT ERROR:
|
||||
copy reset copy
|
||||
running----+ |--------------------+------> EXIT
|
||||
\ /
|
||||
candidate +--------------------+
|
||||
|
||||
* @note: if commit fails, copy candidate to running and exit
|
||||
* @param[in] ret Return value from xml validation function
|
||||
* @param[out] status Transform status according to rules below
|
||||
* @retval 0 OK, status set
|
||||
* @retval -1 Fatal error outside scope of startup_status
|
||||
* Transformation rules:
|
||||
* 1) retval -1 assume clicon_errno/suberrno set. Special case from xml parser
|
||||
* is clicon_suberrno = XMLPARSE_ERRNO which assumes an XML (non-fatal) parse
|
||||
* error which translates to -> STARTUP_ERR
|
||||
* All other error cases translates to fatal error
|
||||
* 2) retval 0 is xml validation fails -> STARTUP_INVALID
|
||||
* 3) retval 1 is OK -> STARTUP_OK
|
||||
* 4) any other retval translates to fatal error
|
||||
*/
|
||||
static int
|
||||
startup_mode_running(clicon_handle h,
|
||||
char *extraxml_file)
|
||||
ret2status(int ret,
|
||||
enum startup_status *status)
|
||||
{
|
||||
int retval = -1;
|
||||
cbuf *cbret = NULL;
|
||||
int retval = -1;
|
||||
|
||||
if ((cbret = cbuf_new()) == NULL){
|
||||
clicon_err(OE_XML, errno, "cbuf_new");
|
||||
goto done;
|
||||
}
|
||||
/* Stash original running to candidate for later commit */
|
||||
if (xmldb_copy(h, "running", "candidate") < 0)
|
||||
goto done;
|
||||
/* Load plugins and call plugin_init() */
|
||||
if (backend_plugin_initiate(h) != 0)
|
||||
goto done;
|
||||
/* Clear tmp db */
|
||||
if (db_reset(h, "tmp") < 0)
|
||||
goto done;
|
||||
/* Application may define extra xml in its reset function*/
|
||||
if (clixon_plugin_reset(h, "tmp") < 0)
|
||||
goto done;
|
||||
/* XXX Kludge to low-level functions to search for xml in all yang modules */
|
||||
_CLICON_XML_NS_STRICT = 0;
|
||||
/* Get application extra xml from file */
|
||||
if (load_extraxml(h, extraxml_file, "tmp", cbret) < 1)
|
||||
goto fail;
|
||||
/* Clear running db */
|
||||
if (db_reset(h, "running") < 0)
|
||||
goto done;
|
||||
/* Commit original running. Assume -1 is validate fail */
|
||||
if (candidate_commit(h, "candidate", cbret) < 1)
|
||||
goto fail;
|
||||
/* Merge user reset state and extra xml file (no commit) */
|
||||
if (db_merge(h, "tmp", "running", cbret) < 1)
|
||||
goto fail;
|
||||
switch (ret){
|
||||
case -1:
|
||||
if (clicon_suberrno != XMLPARSE_ERRNO)
|
||||
goto done;
|
||||
clicon_err_reset();
|
||||
*status = STARTUP_ERR;
|
||||
break;
|
||||
case 0:
|
||||
*status = STARTUP_INVALID;
|
||||
break;
|
||||
case 1:
|
||||
*status = STARTUP_OK;
|
||||
break;
|
||||
default:
|
||||
clicon_err(OE_CFG, EINVAL, "No such retval %d", retval);
|
||||
} /* switch */
|
||||
retval = 0;
|
||||
done:
|
||||
/* XXX Kludge to low-level functions to search for xml in all yang modules */
|
||||
_CLICON_XML_NS_STRICT = clicon_option_bool(h, "CLICON_XML_NS_STRICT");
|
||||
if (cbret)
|
||||
cbuf_free(cbret);
|
||||
if (xmldb_delete(h, "tmp") < 0)
|
||||
goto done;
|
||||
return retval;
|
||||
fail:
|
||||
/* (1) We cannot differentiate between fatal errors and validation
|
||||
* failures
|
||||
* (2) If fatal error, we should exit
|
||||
* (3) If validation fails we cannot continue. How could we?
|
||||
* (4) Need to restore the running db since we destroyed it above
|
||||
*/
|
||||
if (strlen(cbuf_get(cbret)))
|
||||
clicon_log(LOG_NOTICE, "%s: Commit of running failed, exiting: %s.",
|
||||
__FUNCTION__, cbuf_get(cbret));
|
||||
else
|
||||
clicon_log(LOG_NOTICE, "%s: Commit of running failed, exiting: %s.",
|
||||
__FUNCTION__, clicon_err_reason);
|
||||
/* Reinstate original */
|
||||
if (xmldb_copy(h, "candidate", "running") < 0)
|
||||
goto done;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*! Clixon startup startup mode: Commit startup configuration into running state
|
||||
|
||||
|
||||
backup +--------------------|
|
||||
copy / reset commit merge
|
||||
running |-+----|--------------------+-----+------>
|
||||
/ /
|
||||
startup -------------------------+--> /
|
||||
/
|
||||
tmp -----|-------+-----+---------+--|
|
||||
reset extra file
|
||||
|
||||
COMMIT ERROR:
|
||||
backup +------------------------+--|
|
||||
copy / reset copy \
|
||||
running |-+----|--------------------+---+------->EXIT
|
||||
error /
|
||||
startup -------------------------+--|
|
||||
|
||||
* @note: if commit fails, copy backup to commit and exit
|
||||
/*! usage
|
||||
*/
|
||||
static int
|
||||
startup_mode_startup(clicon_handle h,
|
||||
char *extraxml_file)
|
||||
static void
|
||||
usage(clicon_handle h,
|
||||
char *argv0)
|
||||
{
|
||||
int retval = -1;
|
||||
cbuf *cbret = NULL;
|
||||
char *plgdir = clicon_backend_dir(h);
|
||||
char *confsock = clicon_sock(h);
|
||||
char *confpid = clicon_backend_pidfile(h);
|
||||
char *group = clicon_sock_group(h);
|
||||
|
||||
/* Create return buffer for netconf xml errors */
|
||||
if ((cbret = cbuf_new()) == NULL){
|
||||
clicon_err(OE_XML, errno, "cbuf_new");
|
||||
goto done;
|
||||
}
|
||||
/* Stash original running to backup */
|
||||
if (xmldb_copy(h, "running", "backup") < 0)
|
||||
goto done;
|
||||
/* If startup does not exist, clear it */
|
||||
if (xmldb_exists(h, "startup") != 1) /* diff */
|
||||
if (xmldb_create(h, "startup") < 0) /* diff */
|
||||
return -1;
|
||||
/* Load plugins and call plugin_init() */
|
||||
if (backend_plugin_initiate(h) != 0)
|
||||
goto done;
|
||||
/* Clear tmp db */
|
||||
if (db_reset(h, "tmp") < 0)
|
||||
goto done;
|
||||
/* Application may define extra xml in its reset function*/
|
||||
if (clixon_plugin_reset(h, "tmp") < 0)
|
||||
goto done;
|
||||
/* XXX Kludge to low-level functions to search for xml in all yang modules */
|
||||
_CLICON_XML_NS_STRICT = 0;
|
||||
/* Get application extra xml from file */
|
||||
if (load_extraxml(h, extraxml_file, "tmp", cbret) < 1)
|
||||
goto fail;
|
||||
/* Clear running db */
|
||||
if (db_reset(h, "running") < 0)
|
||||
goto done;
|
||||
fprintf(stderr, "usage:%s <options>*\n"
|
||||
"where options are\n"
|
||||
"\t-h\t\tHelp\n"
|
||||
"\t-D <level>\tDebug level\n"
|
||||
"\t-f <file>\tCLICON config file\n"
|
||||
"\t-l (s|e|o|f<file>) Log on (s)yslog, std(e)rr or std(o)ut (stderr is default) Only valid if -F, if background syslog is on syslog.\n"
|
||||
"\t-d <dir>\tSpecify backend plugin directory (default: %s)\n"
|
||||
"\t-p <dir>\tYang directory path (see CLICON_YANG_DIR)\n"
|
||||
"\t-b <dir>\tSpecify XMLDB database directory\n"
|
||||
"\t-F\t\tRun in foreground, do not run as daemon\n"
|
||||
"\t-z\t\tKill other config daemon and exit\n"
|
||||
"\t-a UNIX|IPv4|IPv6 Internal backend socket family\n"
|
||||
"\t-u <path|addr>\tInternal socket domain path or IP addr (see -a)(default: %s)\n"
|
||||
"\t-P <file>\tPid filename (default: %s)\n"
|
||||
"\t-1\t\tRun once and then quit (dont wait for events)\n"
|
||||
"\t-s <mode>\tSpecify backend startup mode: none|startup|running|init)\n"
|
||||
"\t-c <file>\tLoad extra xml configuration, but don't commit.\n"
|
||||
"\t-g <group>\tClient membership required to this group (default: %s)\n"
|
||||
|
||||
/* Commit startup */
|
||||
if (candidate_commit(h, "startup", cbret) < 1) /* diff */
|
||||
goto fail;
|
||||
/* Merge user reset state and extra xml file (no commit) */
|
||||
if (db_merge(h, "tmp", "running", cbret) < 1)
|
||||
goto fail;
|
||||
retval = 0;
|
||||
done:
|
||||
/* XXX Kludge to low-level functions to search for xml in all yang modules */
|
||||
_CLICON_XML_NS_STRICT = clicon_option_bool(h, "CLICON_XML_NS_STRICT");
|
||||
if (cbret)
|
||||
cbuf_free(cbret);
|
||||
if (xmldb_delete(h, "backup") < 0)
|
||||
goto done;
|
||||
if (xmldb_delete(h, "tmp") < 0)
|
||||
goto done;
|
||||
return retval;
|
||||
fail:
|
||||
/* We cannot differentiate between fatal errors and validation
|
||||
* failures
|
||||
* In both cases we copy back the original running and quit
|
||||
*/
|
||||
if (strlen(cbuf_get(cbret)))
|
||||
clicon_log(LOG_NOTICE, "%s: Commit of startup failed, exiting: %s.",
|
||||
__FUNCTION__, cbuf_get(cbret));
|
||||
else
|
||||
clicon_log(LOG_NOTICE, "%s: Commit of startup failed, exiting: %s.",
|
||||
__FUNCTION__, clicon_err_reason);
|
||||
if (xmldb_copy(h, "backup", "running") < 0)
|
||||
goto done;
|
||||
goto done;
|
||||
"\t-y <file>\tLoad yang spec file (override yang main module)\n"
|
||||
"\t-x <plugin>\tXMLDB plugin\n"
|
||||
"\t-o \"<option>=<value>\"\tGive configuration option overriding config file (see clixon-config.yang)\n",
|
||||
argv0,
|
||||
plgdir ? plgdir : "none",
|
||||
confsock ? confsock : "none",
|
||||
confpid ? confpid : "none",
|
||||
group ? group : "none"
|
||||
);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
int
|
||||
|
|
@ -586,6 +341,9 @@ main(int argc,
|
|||
yang_spec *yspecfg = NULL; /* For config XXX clixon bug */
|
||||
char *str;
|
||||
int ss = -1; /* server socket */
|
||||
cbuf *cbret = NULL; /* startup cbuf if invalid */
|
||||
enum startup_status status = STARTUP_ERR; /* Startup status */
|
||||
int ret;
|
||||
|
||||
/* In the startup, logs to stderr & syslog and debug flag set later */
|
||||
clicon_log_init(__PROGRAM__, LOG_INFO, logdst);
|
||||
|
|
@ -796,7 +554,7 @@ main(int argc,
|
|||
}
|
||||
|
||||
if (group_name2gid(config_group, NULL) < 0){
|
||||
clicon_log(LOG_ERR, "'%s' does not seem to be a valid user group.\n"
|
||||
clicon_log(LOG_ERR, "'%s' does not seem to be a valid user group.\n" /* \n required here due to multi-line log */
|
||||
"The config demon requires a valid group to create a server UNIX socket\n"
|
||||
"Define a valid CLICON_SOCK_GROUP in %s or via the -g option\n"
|
||||
"or create the group and add the user to it. On linux for example:"
|
||||
|
|
@ -815,7 +573,7 @@ main(int argc,
|
|||
stream_publish_init() < 0)
|
||||
goto done;
|
||||
if ((xmldb_plugin = clicon_xmldb_plugin(h)) == NULL){
|
||||
clicon_log(LOG_ERR, "No xmldb plugin given (specify option CLICON_XMLDB_PLUGIN).\n");
|
||||
clicon_log(LOG_ERR, "No xmldb plugin given (specify option CLICON_XMLDB_PLUGIN).");
|
||||
goto done;
|
||||
}
|
||||
if (xmldb_plugin_load(h, xmldb_plugin) < 0)
|
||||
|
|
@ -876,10 +634,14 @@ main(int argc,
|
|||
goto done;
|
||||
if (xmldb_setopt(h, "nacm_xtree", (void*)clicon_nacm_ext(h)) < 0)
|
||||
goto done;
|
||||
|
||||
/* Save modules state of the backend (server). Compare with startup XML */
|
||||
if (startup_module_state(h, yspec) < 0)
|
||||
goto done;
|
||||
/* Startup mode needs to be defined, */
|
||||
startup_mode = clicon_startup_mode(h);
|
||||
if (startup_mode == -1){
|
||||
clicon_log(LOG_ERR, "Startup mode undefined. Specify option CLICON_STARTUP_MODE or specify -s option to clicon_backend.\n");
|
||||
clicon_log(LOG_ERR, "Startup mode undefined. Specify option CLICON_STARTUP_MODE or specify -s option to clicon_backend.");
|
||||
goto done;
|
||||
}
|
||||
/* Init running db if it is not there
|
||||
|
|
@ -887,27 +649,59 @@ main(int argc,
|
|||
if (xmldb_exists(h, "running") != 1)
|
||||
if (xmldb_create(h, "running") < 0)
|
||||
return -1;
|
||||
switch (startup_mode){
|
||||
case SM_NONE:
|
||||
if (startup_mode_none(h) < 0)
|
||||
goto done;
|
||||
break;
|
||||
case SM_INIT: /* -I */
|
||||
if (startup_mode_init(h) < 0)
|
||||
goto done;
|
||||
break;
|
||||
case SM_RUNNING: /* -CIr */
|
||||
if (startup_mode_running(h, extraxml_file) < 0)
|
||||
goto done;
|
||||
break;
|
||||
case SM_STARTUP: /* startup configuration */
|
||||
if (startup_mode_startup(h, extraxml_file) < 0)
|
||||
goto done;
|
||||
break;
|
||||
/* If startup fails, lib functions report invalidation info in a cbuf */
|
||||
if ((cbret = cbuf_new()) == NULL){
|
||||
clicon_err(OE_XML, errno, "cbuf_new");
|
||||
goto done;
|
||||
}
|
||||
switch (startup_mode){
|
||||
case SM_INIT: /* Scratch running and start from empty */
|
||||
/* [Delete and] create running db */
|
||||
if (startup_db_reset(h, "running") < 0)
|
||||
goto done;
|
||||
case SM_NONE: /* Fall through *
|
||||
* Load plugins and call plugin_init() */
|
||||
if (backend_plugin_initiate(h) != 0)
|
||||
goto done;
|
||||
status = STARTUP_OK;
|
||||
break;
|
||||
case SM_RUNNING: /* Use running as startup */
|
||||
/* Copy original running to startup and treat as startup */
|
||||
if (xmldb_copy(h, "running", "startup") < 0)
|
||||
goto done;
|
||||
case SM_STARTUP: /* Fall through */
|
||||
/* Load and commit from startup */
|
||||
ret = startup_mode_startup(h, cbret);
|
||||
if (ret2status(ret, &status) < 0)
|
||||
goto done;
|
||||
/* if status = STARTUP_INVALID, cbret contains info */
|
||||
}
|
||||
/* Merge extra XML from file and reset function to running
|
||||
*/
|
||||
if (status == STARTUP_OK && startup_mode != SM_NONE){
|
||||
if ((ret = startup_extraxml(h, extraxml_file, cbret)) < 0)
|
||||
goto done;
|
||||
if (ret2status(ret, &status) < 0)
|
||||
goto done;
|
||||
/* if status = STARTUP_INVALID, cbret contains info */
|
||||
}
|
||||
|
||||
if (status != STARTUP_OK){
|
||||
if (startup_failsafe(h) < 0){
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
/* Initiate the shared candidate. */
|
||||
if (xmldb_copy(h, "running", "candidate") < 0)
|
||||
goto done;
|
||||
/* Set startup status */
|
||||
if (clicon_startup_status_set(h, status) < 0)
|
||||
goto done;
|
||||
|
||||
if (status == STARTUP_INVALID && cbuf_len(cbret))
|
||||
clicon_log(LOG_NOTICE, "%s: %u %s", __PROGRAM__, getpid(), cbuf_get(cbret));
|
||||
|
||||
/* Call backend plugin_start with user -- options */
|
||||
if (plugin_start_useroptions(h, argv0, argc, argv) <0)
|
||||
goto done;
|
||||
|
|
@ -952,6 +746,8 @@ main(int argc,
|
|||
goto done;
|
||||
retval = 0;
|
||||
done:
|
||||
if (cbret)
|
||||
cbuf_free(cbret);
|
||||
clicon_log(LOG_NOTICE, "%s: %u Terminated retval:%d", __PROGRAM__, getpid(), retval);
|
||||
backend_terminate(h); /* Cannot use h after this */
|
||||
|
||||
|
|
|
|||
|
|
@ -157,6 +157,31 @@ clixon_plugin_statedata(clicon_handle h,
|
|||
return retval;
|
||||
}
|
||||
|
||||
/*! Call configuration upgrade routines in backend plugins
|
||||
* @param[in] h Clicon handle
|
||||
* @param[in] xms XML tree of module state differences
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error in one (first) of user callbacks
|
||||
*/
|
||||
int
|
||||
clixon_plugin_upgrade(clicon_handle h,
|
||||
cxobj *xmodst)
|
||||
{
|
||||
int retval = -1;
|
||||
clixon_plugin *cp = NULL;
|
||||
upgrade_cb_t *fn; /* Plugin configuration upgrade fn */
|
||||
|
||||
while ((cp = clixon_plugin_each(h, cp)) != NULL) {
|
||||
if ((fn = cp->cp_api.ca_upgrade) == NULL)
|
||||
continue;
|
||||
if (fn(h, xmodst) < 0)
|
||||
goto done;
|
||||
}
|
||||
retval = 0;
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Create and initialize transaction */
|
||||
transaction_data_t *
|
||||
transaction_new(void)
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ int backend_plugin_initiate(clicon_handle h);
|
|||
int clixon_plugin_reset(clicon_handle h, char *db);
|
||||
|
||||
int clixon_plugin_statedata(clicon_handle h, yang_spec *yspec, char *xpath, cxobj **xtop);
|
||||
|
||||
int clixon_plugin_upgrade(clicon_handle h, cxobj *xmodst);
|
||||
transaction_data_t * transaction_new(void);
|
||||
int transaction_free(transaction_data_t *);
|
||||
|
||||
|
|
|
|||
|
|
@ -152,7 +152,7 @@ config_socket_init_unix(clicon_handle h,
|
|||
return -1;
|
||||
#if 0
|
||||
if (gid == 0)
|
||||
clicon_log(LOG_WARNING, "%s: No such group: %s\n", __FUNCTION__, config_group);
|
||||
clicon_log(LOG_WARNING, "%s: No such group: %s", __FUNCTION__, config_group);
|
||||
#endif
|
||||
/* create unix socket */
|
||||
if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
|
||||
|
|
|
|||
340
apps/backend/backend_startup.c
Normal file
340
apps/backend/backend_startup.c
Normal file
|
|
@ -0,0 +1,340 @@
|
|||
/*
|
||||
*
|
||||
***** BEGIN LICENSE BLOCK *****
|
||||
|
||||
Copyright (C) 2009-2019 Olof Hagsand and Benny Holmgren
|
||||
|
||||
This file is part of CLIXON.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
Alternatively, the contents of this file may be used under the terms of
|
||||
the GNU General Public License Version 3 or later (the "GPL"),
|
||||
in which case the provisions of the GPL are applicable instead
|
||||
of those above. If you wish to allow use of your version of this file only
|
||||
under the terms of the GPL, and not to allow others to
|
||||
use your version of this file under the terms of Apache License version 2,
|
||||
indicate your decision by deleting the provisions above and replace them with
|
||||
the notice and other provisions required by the GPL. If you do not delete
|
||||
the provisions above, a recipient may use your version of this file under
|
||||
the terms of any one of the Apache License version 2 or the GPL.
|
||||
|
||||
***** END LICENSE BLOCK *****
|
||||
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "clixon_config.h" /* generated by config & autoconf */
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <stdarg.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <fcntl.h>
|
||||
#include <time.h>
|
||||
#include <pwd.h>
|
||||
#include <syslog.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/types.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <assert.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
/* cligen */
|
||||
#include <cligen/cligen.h>
|
||||
|
||||
/* clicon */
|
||||
#include <clixon/clixon.h>
|
||||
|
||||
#include "clixon_backend_transaction.h"
|
||||
#include "backend_plugin.h"
|
||||
#include "backend_handle.h"
|
||||
#include "backend_commit.h"
|
||||
#include "backend_startup.h"
|
||||
|
||||
/*! Create an XML database. If it exists already, delete it before creating
|
||||
* @param[in] h Clixon handle
|
||||
* @param[in] db Symbolic database name, eg "candidate", "running"
|
||||
*/
|
||||
int
|
||||
startup_db_reset(clicon_handle h,
|
||||
char *db)
|
||||
{
|
||||
if (xmldb_exists(h, db) == 1){
|
||||
if (xmldb_delete(h, db) != 0 && errno != ENOENT)
|
||||
return -1;
|
||||
}
|
||||
if (xmldb_create(h, db) < 0)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! Merge db1 into db2 without commit
|
||||
* @retval -1 Error
|
||||
* @retval 0 Validation failed (with cbret set)
|
||||
* @retval 1 Validation OK
|
||||
*/
|
||||
static int
|
||||
db_merge(clicon_handle h,
|
||||
const char *db1,
|
||||
const char *db2,
|
||||
cbuf *cbret)
|
||||
{
|
||||
int retval = -1;
|
||||
cxobj *xt = NULL;
|
||||
|
||||
/* Get data as xml from db1 */
|
||||
if (xmldb_get(h, (char*)db1, NULL, 1, &xt, NULL) < 0)
|
||||
goto done;
|
||||
/* Merge xml into db2. Without commit */
|
||||
retval = xmldb_put(h, (char*)db2, OP_MERGE, xt, clicon_username_get(h), cbret);
|
||||
done:
|
||||
if (xt)
|
||||
xml_free(xt);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Clixon startup startup mode: Commit startup configuration into running state
|
||||
* @param[in] h Clixon handle
|
||||
* @param[out] cbret If status is invalid contains error message
|
||||
* @retval -1 Error
|
||||
* @retval 0 Validation failed
|
||||
* @retval 1 OK
|
||||
|
||||
OK:
|
||||
reset
|
||||
running |--------+------------> RUNNING
|
||||
parse validate OK / commit
|
||||
startup -------+--+-------+------------+
|
||||
|
||||
|
||||
INVALID (requires manual edit of candidate)
|
||||
failsafe ----------------------+
|
||||
reset \ commit
|
||||
running |-------+---------------> RUNNING FAILSAFE
|
||||
parse validate fail
|
||||
startup ---+-------------------------------------> INVALID XML
|
||||
|
||||
ERR: (requires repair of startup) NYI
|
||||
failsafe ----------------------+
|
||||
reset \ commit
|
||||
running |-------+---------------> RUNNING FAILSAFE
|
||||
parse fail
|
||||
startup --+-------------------------------------> BROKEN XML
|
||||
|
||||
* @note: if commit fails, copy factory to running
|
||||
*/
|
||||
int
|
||||
startup_mode_startup(clicon_handle h,
|
||||
cbuf *cbret)
|
||||
{
|
||||
int retval = -1;
|
||||
int ret;
|
||||
char *db = "startup";
|
||||
|
||||
/* [Delete and] create running db */
|
||||
if (startup_db_reset(h, "running") < 0)
|
||||
goto done;
|
||||
/* Load plugins and call plugin_init() */
|
||||
if (backend_plugin_initiate(h) != 0)
|
||||
goto done;
|
||||
/* If startup does not exist, create it empty */
|
||||
if (xmldb_exists(h, db) != 1){ /* diff */
|
||||
if (xmldb_create(h, db) < 0) /* diff */
|
||||
return -1;
|
||||
}
|
||||
if ((ret = startup_validate(h, db, cbret)) < 0)
|
||||
goto done;
|
||||
if (ret == 0)
|
||||
goto fail;
|
||||
/* Commit startup */
|
||||
if (candidate_commit(h, db, cbret) < 1) /* diff */
|
||||
goto fail;
|
||||
if (ret == 0) /* shouldnt happen (we already validate) */
|
||||
goto fail;
|
||||
retval = 1;
|
||||
done:
|
||||
return retval;
|
||||
fail:
|
||||
retval = 0;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*! Merge xml in filename into database
|
||||
* @retval -1 Error
|
||||
* @retval 0 Validation failed (with cbret set)
|
||||
* @retval 1 Validation OK
|
||||
*/
|
||||
static int
|
||||
load_extraxml(clicon_handle h,
|
||||
char *filename,
|
||||
const char *db,
|
||||
cbuf *cbret)
|
||||
{
|
||||
int retval = -1;
|
||||
cxobj *xt = NULL;
|
||||
int fd = -1;
|
||||
|
||||
if (filename == NULL)
|
||||
return 1;
|
||||
if ((fd = open(filename, O_RDONLY)) < 0){
|
||||
clicon_err(OE_UNIX, errno, "open(%s)", filename);
|
||||
goto done;
|
||||
}
|
||||
if (xml_parse_file(fd, "</config>", NULL, &xt) < 0)
|
||||
goto done;
|
||||
/* Replace parent w first child */
|
||||
if (xml_rootchild(xt, 0, &xt) < 0)
|
||||
goto done;
|
||||
/* Merge user reset state */
|
||||
retval = xmldb_put(h, (char*)db, OP_MERGE, xt, clicon_username_get(h), cbret);
|
||||
done:
|
||||
if (fd != -1)
|
||||
close(fd);
|
||||
if (xt)
|
||||
xml_free(xt);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Load extra XML via file and/or reset callback, and merge with current
|
||||
* An application can add extra XML either via the -c <file> option or
|
||||
* via the .ca_reset callback. This XML is "merged" into running, that is,
|
||||
* it does not trigger validation calbacks.
|
||||
* The function uses an extra "tmp" database, loads the file to it, and calls
|
||||
* the reset function on it.
|
||||
* @param[in] h Clicon handle
|
||||
* @param[in] file (Optional) extra xml file
|
||||
* @param[out] status Startup status
|
||||
* @param[out] cbret If status is invalid contains error message
|
||||
* @retval -1 Error
|
||||
* @retval 0 Validation failed
|
||||
* @retval 1 OK
|
||||
|
||||
running -----------------+----+------>
|
||||
reset loadfile / merge
|
||||
tmp |-------+-----+-----+
|
||||
reset extrafile
|
||||
*/
|
||||
int
|
||||
startup_extraxml(clicon_handle h,
|
||||
char *file,
|
||||
cbuf *cbret)
|
||||
{
|
||||
int retval = -1;
|
||||
char *db = "tmp";
|
||||
int ret;
|
||||
|
||||
/* Clear tmp db */
|
||||
if (startup_db_reset(h, db) < 0)
|
||||
goto done;
|
||||
/* Application may define extra xml in its reset function*/
|
||||
if (clixon_plugin_reset(h, db) < 0)
|
||||
goto done;
|
||||
/* Extra XML can also be added via file */
|
||||
if (file){
|
||||
/* Parse and load file into tmp db */
|
||||
if ((ret = load_extraxml(h, file, db, cbret)) < 0)
|
||||
goto done;
|
||||
if (ret == 0)
|
||||
goto fail;
|
||||
}
|
||||
/* Validate tmp (unless empty?) */
|
||||
if ((ret = startup_validate(h, db, cbret)) < 0)
|
||||
goto done;
|
||||
if (ret == 0)
|
||||
goto fail;
|
||||
/* Merge tmp into running (no commit) */
|
||||
if ((ret = db_merge(h, db, "running", cbret)) < 0)
|
||||
goto fail;
|
||||
if (ret == 0)
|
||||
goto fail;
|
||||
retval = 1;
|
||||
done:
|
||||
if (xmldb_delete(h, "tmp") != 0 && errno != ENOENT)
|
||||
return -1;
|
||||
return retval;
|
||||
fail:
|
||||
retval = 0;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*! Reset running and start in failsafe mode. If no failsafe then quit.
|
||||
Typically done when startup status is not OK so
|
||||
|
||||
failsafe ----------------------+
|
||||
reset \ commit
|
||||
running |-------+---------------> RUNNING FAILSAFE
|
||||
*/
|
||||
int
|
||||
startup_failsafe(clicon_handle h)
|
||||
{
|
||||
int retval = -1;
|
||||
int ret;
|
||||
char *db = "failsafe";
|
||||
cbuf *cbret = NULL;
|
||||
|
||||
if ((cbret = cbuf_new()) == NULL){
|
||||
clicon_err(OE_XML, errno, "cbuf_new");
|
||||
goto done;
|
||||
}
|
||||
if (startup_db_reset(h, "running") < 0)
|
||||
goto done;
|
||||
if ((ret = xmldb_exists(h, db)) < 0)
|
||||
goto done;
|
||||
if (ret == 0){ /* No it does not exist, fail */
|
||||
clicon_err(OE_DB, 0, "No failsafe database");
|
||||
goto done;
|
||||
}
|
||||
if ((ret = candidate_commit(h, db, cbret)) < 0) /* diff */
|
||||
goto done;
|
||||
if (ret == 0){
|
||||
clicon_err(OE_DB, 0, "Failsafe database validation failed %s", cbuf_get(cbret));
|
||||
goto done;
|
||||
}
|
||||
retval = 0;
|
||||
done:
|
||||
if (cbret)
|
||||
cbuf_free(cbret);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Init modules state of the backend (server). To compare with startup XML
|
||||
* Set the modules state as setopt to the datastore module.
|
||||
*/
|
||||
int
|
||||
startup_module_state(clicon_handle h,
|
||||
yang_spec *yspec)
|
||||
{
|
||||
int retval = -1;
|
||||
cxobj *x = NULL;
|
||||
|
||||
if (yang_modules_state_get(h, yspec, NULL, 1, &x) < 0)
|
||||
goto done;
|
||||
if (x){
|
||||
if (xml_rootchild(x, 0, &x) < 0)
|
||||
goto done;
|
||||
if (xmldb_setopt(h, "modules_state", (void*)x) < 0)
|
||||
goto done;
|
||||
}
|
||||
retval = 0;
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
49
apps/backend/backend_startup.h
Normal file
49
apps/backend/backend_startup.h
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
*
|
||||
***** BEGIN LICENSE BLOCK *****
|
||||
|
||||
Copyright (C) 2009-2019 Olof Hagsand and Benny Holmgren
|
||||
|
||||
This file is part of CLIXON.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
Alternatively, the contents of this file may be used under the terms of
|
||||
the GNU General Public License Version 3 or later (the "GPL"),
|
||||
in which case the provisions of the GPL are applicable instead
|
||||
of those above. If you wish to allow use of your version of this file only
|
||||
under the terms of the GPL, and not to allow others to
|
||||
use your version of this file under the terms of Apache License version 2,
|
||||
indicate your decision by deleting the provisions above and replace them with
|
||||
the notice and other provisions required by the GPL. If you do not delete
|
||||
the provisions above, a recipient may use your version of this file under
|
||||
the terms of any one of the Apache License version 2 or the GPL.
|
||||
|
||||
***** END LICENSE BLOCK *****
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _BACKEND_STARTUP_H_
|
||||
#define _BACKEND_STARTUP_H_
|
||||
|
||||
/*
|
||||
* Prototypes
|
||||
*/
|
||||
int startup_db_reset(clicon_handle h, char *db);
|
||||
int startup_mode_startup(clicon_handle h, cbuf *cbret);
|
||||
int startup_extraxml(clicon_handle h, char *file, cbuf *cbret);
|
||||
int startup_failsafe(clicon_handle h);
|
||||
int startup_module_state(clicon_handle h, yang_spec *yspec);
|
||||
|
||||
#endif /* _BACKEND_STARTUP_H_ */
|
||||
Loading…
Add table
Add a link
Reference in a new issue