Split config into multiple sub-files on mount-point boundaries and dont write clean subfiles

Added CLICON_XMLDB_MULTI option, added cl:xmldb-split extension
This commit is contained in:
Olof hagsand 2024-04-16 12:19:15 +02:00
parent bd290e4594
commit f511cb0030
30 changed files with 1311 additions and 285 deletions

View file

@ -86,6 +86,17 @@
#define handle(xh) (assert(text_handle_check(xh)==0),(struct text_handle *)(xh))
/* Local types */
/* Argument to apply for recursive call to xmldb_multi calls
* @see xmldb_multi_write_arg
*/
struct xmldb_multi_read_arg {
char *mr_subdir;
yang_stmt *mr_yspec;
enum format_enum mr_format;
cxobj **mr_xerr;
};
/*! Ensure that xt only has a single sub-element and that is "config"
*
* @retval 0 There exists a single "config" sub-element
@ -446,6 +457,68 @@ disable_nacm_on_empty(cxobj *xt,
return retval;
}
/*! Callback function for xmldb-multi read
*
* Look for link attribute in XML, and if found open the linked file for parsing
* @param[in] x XML node
* @param[in] arg
* @retval 2 Locally abort this subtree, continue with others
* @retval 1 Abort, dont continue with others, return 1 to end user
* @retval 0 OK, continue
* @retval -1 Error, aborted at first error encounter, return -1 to end user
*/
static int
xmldb_multi_read_applyfn(cxobj *x,
void *arg)
{
struct xmldb_multi_read_arg *mr = (struct xmldb_multi_read_arg *) arg;
int retval = -1;
cxobj *xa;
char *filename;
cbuf *cb = NULL;
char *dbfile;
FILE *fp = NULL;
if ((xa = xml_find_type(x, CLIXON_LIB_PREFIX, "link", CX_ATTR)) != NULL &&
(filename = xml_value(xa)) != NULL){
if ((cb = cbuf_new()) == NULL){
clixon_err(OE_XML, errno, "cbuf_new");
goto done;
}
cprintf(cb, "%s/%s", mr->mr_subdir, filename);
xml_purge(xa);
if ((xa = xml_find_type(x, "xmlns", CLIXON_LIB_PREFIX, CX_ATTR)) != NULL)
xml_purge(xa);
dbfile = cbuf_get(cb);
clixon_debug(CLIXON_DBG_DATASTORE, "Parsing: %s", dbfile);
if ((fp = fopen(dbfile, "r")) == NULL){
clixon_err(OE_CFG, errno, "fdopen(%s)", dbfile);
goto done;
}
switch (mr->mr_format){
case FORMAT_JSON:
if (clixon_json_parse_file(fp, 1, YB_NONE, mr->mr_yspec, &x, mr->mr_xerr) < 0)
goto done;
break;
case FORMAT_XML:
if (clixon_xml_parse_file(fp, YB_NONE, mr->mr_yspec, &x, mr->mr_xerr) < 0)
goto done;
break;
default:
clixon_err(OE_DB, 0, "Format not supported");
goto done;
break;
}
}
retval = 0;
done:
if (cb)
cbuf_free(cb);
if (fp)
fclose(fp);
return retval;
}
/*! Common read function that reads an XML tree from file
*
* @param[in] th Datastore text handle
@ -477,7 +550,8 @@ xmldb_readfile(clixon_handle h,
cxobj *x0 = NULL;
char *dbfile = NULL;
FILE *fp = NULL;
char *format;
char *formatstr;
enum format_enum format;
int ret;
modstate_diff_t *msdiff = NULL;
cxobj *xmsd; /* XML module state diff */
@ -489,6 +563,7 @@ xmldb_readfile(clixon_handle h,
cxobj *xmodfile = NULL;
cxobj *x;
yang_stmt *yspec1 = NULL;
struct xmldb_multi_read_arg mr = {0, };
if (yb != YB_MODULE && yb != YB_NONE){
clixon_err(OE_XML, EINVAL, "yb is %d but should be module or none", yb);
@ -500,11 +575,15 @@ xmldb_readfile(clixon_handle h,
clixon_err(OE_XML, 0, "dbfile NULL");
goto done;
}
if ((format = clicon_option_str(h, "CLICON_XMLDB_FORMAT")) == NULL){
if ((formatstr = clicon_option_str(h, "CLICON_XMLDB_FORMAT")) == NULL){
clixon_err(OE_CFG, ENOENT, "No CLICON_XMLDB_FORMAT");
goto done;
}
clixon_debug(CLIXON_DBG_DATASTORE, "Reading datastore %s using %s", dbfile, format);
if ((format = format_str2int(formatstr)) < 0){
clixon_err(OE_XML, 0, "format not found %s", formatstr);
goto done;
}
clixon_debug(CLIXON_DBG_DATASTORE, "Reading datastore %s using %s", dbfile, formatstr);
/* Parse file into internal XML tree from different formats */
if ((fp = fopen(dbfile, "r")) == NULL) {
clixon_err(OE_UNIX, errno, "open(%s)", dbfile);
@ -516,14 +595,28 @@ xmldb_readfile(clixon_handle h,
* config*
* </config>
* ret == 0 should not happen with YB_NONE. Binding is done later */
if (strcmp(format, "json")==0){
switch (format){
case FORMAT_JSON:
if (clixon_json_parse_file(fp, 1, YB_NONE, yspec, &x0, xerr) < 0)
goto done;
}
else {
if (clixon_xml_parse_file(fp, YB_NONE, yspec, &x0, xerr) < 0){
break;
case FORMAT_XML:
if (clixon_xml_parse_file(fp, YB_NONE, yspec, &x0, xerr) < 0)
goto done;
break;
default:
clixon_err(OE_DB, 0, "Format %s not supported", formatstr);
goto done;
break;
}
if (clicon_option_bool(h, "CLICON_XMLDB_MULTI")){
if (xmldb_db2subdir(h, db, &mr.mr_subdir) < 0)
goto done;
mr.mr_format = format;
mr.mr_yspec = yspec;
mr.mr_xerr = xerr;
if (xml_apply(x0, CX_ELMNT, (xml_applyfn_t*)xmldb_multi_read_applyfn, &mr) < 0)
goto done;
}
}
/* Always assert a top-level called "config".
* To ensure that, deal with two cases:
@ -646,6 +739,8 @@ xmldb_readfile(clixon_handle h,
}
retval = 1;
done:
if (mr.mr_subdir)
free(mr.mr_subdir);
if (yspec1)
ys_free1(yspec1, 1);
if (xmodfile)