Generic map_str2int generic mapping tables; Removed vector return values from xmldb_get()

This commit is contained in:
Olof hagsand 2017-06-21 21:02:09 +02:00
parent bf30e6f66a
commit abd3eee17d
29 changed files with 381 additions and 280 deletions

View file

@ -230,12 +230,14 @@ clicon_rpc_generate_error(cxobj *xerr)
* @param[in] h CLICON handle
* @param[in] db Name of database
* @param[in] xpath XPath (or "")
* @param[in] errmode 0 if xml errors are returned as clicon_err
* 1 if xml errors are in xt and return 0.
* @param[out] xt XML tree. must be freed by caller with xml_free
* @retval 0 OK
* @retval -1 Error, fatal or xml
* @code
* cxobj *xt = NULL;
* if (clicon_rpc_get_config(h, "running", "/", &xt) < 0)
* if (clicon_rpc_get_config(h, "running", "/", 0, &xt) < 0)
* err;
* if (xt)
* xml_free(xt);
@ -245,6 +247,7 @@ int
clicon_rpc_get_config(clicon_handle h,
char *db,
char *xpath,
int errmode,
cxobj **xt)
{
int retval = -1;
@ -264,13 +267,22 @@ clicon_rpc_get_config(clicon_handle h,
goto done;
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
goto done;
if ((xerr = xpath_first(xret, "//rpc-error")) != NULL){
clicon_rpc_generate_error(xerr);
goto done;
}
if ((xd = xpath_first(xret, "//data/config")) == NULL)
if ((xd = xml_new("config", NULL)) == NULL)
if (errmode == 0){ /* Move this to caller */
if ((xerr = xpath_first(xret, "//rpc-error")) != NULL){
clicon_rpc_generate_error(xerr);
goto done;
}
if ((xd = xpath_first(xret, "//data/config")) == NULL)
if ((xd = xml_new("config", NULL)) == NULL)
goto done;
}
else{ /* Send xml error back (this should be default behaviour) */
if ((xd = xpath_first(xret, "//rpc-error")) == NULL){
if ((xd = xpath_first(xret, "//data/config")) == NULL)
if ((xd = xml_new("config", NULL)) == NULL)
goto done;
}
}
if (xt){
if (xml_rm(xd) < 0)
goto done;

View file

@ -333,6 +333,43 @@ str2cvec(char *string,
goto done;
}
/*! Map from int to string using str2int map
* @param[in] ms String, integer map
* @param[in] i Input integer
* @retval str String value
* @retval NULL Error, not found
* @note linear search
*/
const char *
clicon_int2str(const map_str2int *mstab,
int i)
{
const struct map_str2int *ms;
for (ms = &mstab[0]; ms->ms_str; ms++)
if (ms->ms_int == i)
return ms->ms_str;
return NULL;
}
/*! Map from string to int using str2int map
* @param[in] ms String, integer map
* @param[in] str Input string
* @retval int Value
* @retval -1 Error, not found
* @note linear search
*/
int
clicon_str2int(const map_str2int *mstab,
char *str)
{
const struct map_str2int *ms;
for (ms = &mstab[0]; ms->ms_str; ms++)
if (strcmp(ms->ms_str, str) == 0)
return ms->ms_int;
return -1;
}
/*! strndup() for systems without it, such as xBSD
*/

View file

@ -50,6 +50,7 @@
/* clixon */
#include "clixon_err.h"
#include "clixon_log.h"
#include "clixon_string.h"
#include "clixon_queue.h"
#include "clixon_xml.h"
#include "clixon_xml_parse.h"
@ -82,14 +83,8 @@ struct xml{
cg_var *x_cv; /* If body this contains the typed value */
};
/* Type to string conversion */
struct map_str2int{
char *ms_str;
enum cxobj_type ms_type;
};
/* Mapping between xml type <--> string */
static const struct map_str2int xsmap[] = {
static const map_str2int xsmap[] = {
{"error", CX_ERROR},
{"element", CX_ELMNT},
{"attr", CX_ATTR},
@ -104,12 +99,7 @@ static const struct map_str2int xsmap[] = {
char *
xml_type2str(enum cxobj_type type)
{
const struct map_str2int *xs;
for (xs = &xsmap[0]; xs->ms_str; xs++)
if (xs->ms_type == type)
return xs->ms_str;
return NULL;
return (char*)clicon_int2str(xsmap, type);
}
/*

View file

@ -169,6 +169,23 @@ xmldb_plugin_unload(clicon_handle h)
return retval;
}
/*! Validate database name
* @param[in] db Name of database
* @param[out] xret Return value as cligen buffer containing xml netconf return
* @retval 0 OK
* @retval -1 Failed validate, xret set to error
*/
int
xmldb_validate_db(char *db)
{
if (strcmp(db, "running") != 0 &&
strcmp(db, "candidate") != 0 &&
strcmp(db, "startup") != 0 &&
strcmp(db, "tmp") != 0)
return -1;
return 0;
}
/*! Connect to a datastore plugin, allocate handle to be used in API calls
* @param[in] h Clicon handle
* @retval 0 OK
@ -306,23 +323,17 @@ xmldb_setopt(clicon_handle h,
* @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[out] xtop Single XML tree which xvec points to. Free with 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;
* if (xmldb_get(xh, "running", "/interfaces/interface[name="eth"]",
* &xt, &xvec, &xlen) < 0)
* if (xmldb_get(xh, "running", "/interfaces/interface[name="eth"]", &xt) < 0)
* err;
* for (i=0; i<xlen; i++){
* xn = xv[i];
* ...
* }
* xml_free(xt);
* free(xvec);
* @endcode
* @note if xvec is given, then purge tree, if not return whole tree.
* @see xpath_vec
@ -332,9 +343,7 @@ int
xmldb_get(clicon_handle h,
char *db,
char *xpath,
cxobj **xtop,
cxobj ***xvec,
size_t *xlen)
cxobj **xtop)
{
int retval = -1;
xmldb_handle xh;
@ -352,7 +361,7 @@ xmldb_get(clicon_handle h,
clicon_err(OE_DB, 0, "Not connected to datastore plugin");
goto done;
}
retval = xa->xa_get_fn(xh, db, xpath, xtop, xvec, xlen);
retval = xa->xa_get_fn(xh, db, xpath, xtop);
#if DEBUG
if (retval == 0) {
cbuf *cb = cbuf_new();
@ -366,14 +375,12 @@ xmldb_get(clicon_handle h,
return retval;
}
/*! Modify database provided an xml tree and an operation
/*! Modify database given an xml tree and an operation
*
* @param[in] h CLICON handle
* @param[in] db running or candidate
* @param[in] op Top-level operation, can be superceded by other op in tree
* @param[in] xt xml-tree. Top-level symbol is dummy
* @param[in] op OP_MERGE: just add it.
* OP_REPLACE: first delete whole database
* OP_NONE: operation attribute in xml determines operation
* @retval 0 OK
* @retval -1 Error
* The xml may contain the "operation" attribute which defines the operation.
@ -581,7 +588,7 @@ xmldb_islocked(clicon_handle h,
clicon_err(OE_DB, 0, "Not connected to datastore plugin");
goto done;
}
retval =xa->xa_islocked_fn(xh, db);
retval = xa->xa_islocked_fn(xh, db);
done:
return retval;
}

View file

@ -1617,3 +1617,84 @@ api_path2xml(char *api_path,
free(vec);
return retval;
}
/* See RFC 8040 Section 7: Mapping from NETCONF<error-tag> to Status Code
* and RFC 6241 Appendix A. NETCONF Error list
*/
const map_str2int netconf_restconf_map[] = {
{"in-use", 409},
{"invalid-value", 400},
{"invalid-value", 404},
{"invalid-value", 406},
{"too-big", 413}, /* request */
{"too-big", 400}, /* response */
{"missing-attribute", 400},
{"bad-attribute", 400},
{"unknown-attribute", 400},
{"bad-element", 400},
{"unknown-element", 400},
{"unknown-namespace", 400},
{"access-denied", 401},
{"access-denied", 403},
{"lock-denied", 409},
{"resource-denied", 409},
{"rollback-failed", 500},
{"data-exists", 409},
{"data-missing", 409},
{"operation-not-supported",405},
{"operation-not-supported",501},
{"operation-failed", 412},
{"operation-failed", 500},
{"partial-operation", 500},
{"malformed-message", 400},
{NULL, -1}
};
/* See 7231 Section 6.1
*/
const map_str2int http_reason_phrase_map[] = {
{"Continue", 100},
{"Switching Protocols", 101},
{"OK", 200},
{"Created", 201},
{"Accepted", 202},
{"Non-Authoritative Information", 203},
{"No Content", 204},
{"Reset Content", 205},
{"Partial Content", 206},
{"Multiple Choices", 300},
{"Moved Permanently", 301},
{"Found", 302},
{"See Other", 303},
{"Not Modified", 304},
{"Use Proxy", 305},
{"Temporary Redirect", 307},
{"Bad Request", 400},
{"Unauthorized", 401},
{"Payment Required", 402},
{"Forbidden", 403},
{"Not Found", 404},
{"Method Not Allowed", 405},
{"Not Acceptable", 406},
{"Proxy Authentication Required", 407},
{"Request Timeout", 408},
{"Conflict", 409},
{"Gone", 410},
{"Length Required", 411},
{"Precondition Failed", 412},
{"Payload Too Large", 413},
{"URI Too Long", 414},
{"Unsupported Media Type", 415},
{"Range Not Satisfiable", 416},
{"Expectation Failed", 417},
{"Upgrade Required", 426},
{"Internal Server Error", 500},
{"Not Implemented", 501},
{"Bad Gateway", 502},
{"Service Unavailable", 503},
{"Gateway Timeout", 504},
{"HTTP Version Not Supported", 505},
{NULL, -1}
};

View file

@ -100,6 +100,7 @@ in
/* clicon */
#include "clixon_err.h"
#include "clixon_log.h"
#include "clixon_string.h"
#include "clixon_xml.h"
#include "clixon_xsl.h"
@ -130,13 +131,8 @@ enum axis_type{
A_DESCENDANT_OR_SELF, /* actually descendant-or-self */
};
struct map_str2int{
char *ms_str; /* string as in 4.2.4 in RFC 6020 */
int ms_int;
};
/* Mapping between axis type string <--> int */
static const struct map_str2int atmap[] = {
static const map_str2int atmap[] = {
{"self", A_SELF},
{"child", A_CHILD},
{"parent", A_PARENT},
@ -160,19 +156,6 @@ struct xpath_element{
static int xpath_split(char *xpathstr, char **pathexpr);
static char *axis_type2str(enum axis_type type) __attribute__ ((unused));
static char *
axis_type2str(enum axis_type type)
{
const struct map_str2int *at;
for (at = &atmap[0]; at->ms_str; at++)
if (at->ms_int == type)
return at->ms_str;
return NULL;
}
static int
xpath_print(FILE *f, struct xpath_element *xplist)
{
@ -180,7 +163,7 @@ xpath_print(FILE *f, struct xpath_element *xplist)
struct xpath_predicate *xp;
for (xe=xplist; xe; xe=xe->xe_next){
fprintf(f, "\t:%s %s ", axis_type2str(xe->xe_type),
fprintf(f, "\t:%s %s ", clicon_int2str(atmap, xe->xe_type),
xe->xe_str?xe->xe_str:"");
for (xp=xe->xe_predicate; xp; xp=xp->xp_next)
fprintf(f, "[%s]", xp->xp_expr);
@ -598,7 +581,7 @@ xpath_find(struct xpath_element *xe,
}
#if 0
fprintf(stderr, "%s: %s: \"%s\"\n", __FUNCTION__,
axis_type2str(xe->xe_type), xe->xe_str?xe->xe_str:"");
clicon_int2str(atmap, xe->xe_type), xe->xe_str?xe->xe_str:"");
#endif
switch (xe->xe_type){
case A_SELF:

View file

@ -75,21 +75,9 @@
for static scope type binding */
#define YANG_TYPE_CACHE 1
/*
* Private data types
*/
/* Struct used to map between int and strings. Used for:
* - mapping yang types/typedefs (strings) and cligen types (ints).
* - mapping yang keywords (strings) and enum (clicon)
*/
struct map_str2int{
char *ms_str; /* string as in 4.2.4 in RFC 6020 */
int ms_int;
};
/* Mapping between yang keyword string <--> clicon constants */
static const struct map_str2int ykmap[] = {
static const map_str2int ykmap[] = {
{"anyxml", Y_ANYXML},
{"argument", Y_ARGUMENT},
{"augment", Y_AUGMENT},
@ -545,18 +533,10 @@ ys_flag_reset(yang_stmt *ys,
return 0;
}
/*! Translate from RFC 6020 keywords to printable string.
linear search,...
*/
char *
yang_key2str(int keyword)
{
const struct map_str2int *yk;
for (yk = &ykmap[0]; yk->ms_str; yk++)
if (yk->ms_int == keyword)
return yk->ms_str;
return NULL;
return (char*)clicon_int2str(ykmap, keyword);
}
/*! Find top module or sub-module. Note that ultimate top is yang spec

View file

@ -71,19 +71,10 @@
/*
* Local types and variables
*/
/* Struct used to map between int and strings. Used for:
* - mapping yang types/typedefs (strings) and cligen types (ints).
* - mapping yang keywords (strings) and enum (clicon)
* (same struct in clicon_yang.c)
*/
struct map_str2int{
char *ms_str; /* string as in 4.2.4 in RFC 6020 */
int ms_int;
};
/* Mapping between yang types <--> cligen types
Note, first match used wne translating from cv to yang --> order is significant */
static const struct map_str2int ytmap[] = {
static const map_str2int ytmap[] = {
{"int32", CGV_INT32}, /* NOTE, first match on right is significant, dont move */
{"string", CGV_STRING}, /* NOTE, first match on right is significant, dont move */
{"string", CGV_REST}, /* For cv -> yang translation of rest */
@ -105,9 +96,22 @@ static const struct map_str2int ytmap[] = {
{"uint32", CGV_UINT32},
{"uint64", CGV_UINT64},
{"union", CGV_REST}, /* Is replaced by actual type */
{NULL, -1}
{NULL, -1}
};
/* return 1 if built-in, 0 if not */
static int
yang_builtin(char *type)
{
const struct map_str2int *yt;
/* built-in types */
for (yt = &ytmap[0]; yt->ms_str; yt++)
if (strcmp(yt->ms_str, type) == 0)
return 1;
return 0;
}
int
yang_type_cache_set(yang_type_cache **ycache0,
yang_stmt *resolved,
@ -229,20 +233,6 @@ ys_resolve_type(yang_stmt *ys, void *arg)
return retval;
}
/* return 1 if built-in, 0 if not */
static int
yang_builtin(char *type)
{
const struct map_str2int *yt;
/* built-in types */
for (yt = &ytmap[0]; yt->ms_str; yt++)
if (strcmp(yt->ms_str, type) == 0)
return 1;
return 0;
}
/*! Translate from a yang type to a cligen variable type
*
* Currently many built-in types from RFC6020 and some RFC6991 types.
@ -252,17 +242,17 @@ yang_builtin(char *type)
* Return 0 if no match but set cv_type to CGV_ERR
*/
int
yang2cv_type(char *ytype, enum cv_type *cv_type)
yang2cv_type(char *ytype,
enum cv_type *cv_type)
{
const struct map_str2int *yt;
int ret;
*cv_type = CGV_ERR;
/* built-in types */
for (yt = &ytmap[0]; yt->ms_str; yt++)
if (strcmp(yt->ms_str, ytype) == 0){
*cv_type = yt->ms_int;
return 0;
}
if ((ret = clicon_str2int(ytmap, ytype)) != -1){
*cv_type = ret;
return 0;
}
/* special derived types */
if (strcmp("ipv4-address", ytype) == 0){ /* RFC6991 */
*cv_type = CGV_IPV4ADDR;
@ -300,14 +290,13 @@ yang2cv_type(char *ytype, enum cv_type *cv_type)
char *
cv2yang_type(enum cv_type cv_type)
{
const struct map_str2int *yt;
char *ytype;
const char *str;
ytype = "empty";
/* built-in types */
for (yt = &ytmap[0]; yt->ms_str; yt++)
if (yt->ms_int == cv_type)
return yt->ms_str;
if ((str = clicon_int2str(ytmap, cv_type)) != NULL)
return (char*)str;
/* special derived types */
if (cv_type == CGV_IPV4ADDR) /* RFC6991 */