Added --with-cligen and --with-qdbm configure options; union type check for non-cli (eg xml) input

This commit is contained in:
Olof hagsand 2017-01-12 08:39:12 +01:00
parent 319e7707d8
commit 41680474c7
7 changed files with 195 additions and 67 deletions

View file

@ -29,6 +29,8 @@
# #
# ***** END LICENSE BLOCK ***** # ***** END LICENSE BLOCK *****
- Added --with-cligen and --with-qdbm configure options
- Added union type check for non-cli (eg xml) input
- Empty yang type. Relaxed yang types for unions, eg two strings with different length. - Empty yang type. Relaxed yang types for unions, eg two strings with different length.
Dec 2016: Dual license: both GPLv3 and APLv2 Dec 2016: Dual license: both GPLv3 and APLv2

View file

@ -410,7 +410,8 @@ cli_load_syntax(clicon_handle h, const char *filename, const char *clispec_dir)
} }
} }
/* Resolve callback names to function pointers */ /* Resolve callback names to function pointers.
* XXX: consider using cligen_callback_str2fnv instead */
if (cligen_callback_str2fn(pt, load_str2fn, handle) < 0){ if (cligen_callback_str2fn(pt, load_str2fn, handle) < 0){
clicon_err(OE_PLUGIN, 0, "Mismatch between CLIgen file '%s' and CLI plugin file '%s'. Some possible errors:\n\t1. A function given in the CLIgen file does not exist in the plugin (ie link error)\n\t2. The CLIgen spec does not point to the correct plugin .so file (CLICON_PLUGIN=\"%s\" is wrong)", clicon_err(OE_PLUGIN, 0, "Mismatch between CLIgen file '%s' and CLI plugin file '%s'. Some possible errors:\n\t1. A function given in the CLIgen file does not exist in the plugin (ie link error)\n\t2. The CLIgen spec does not point to the correct plugin .so file (CLICON_PLUGIN=\"%s\" is wrong)",
filename, plgnam, plgnam); filename, plgnam, plgnam);

49
configure vendored
View file

@ -701,6 +701,8 @@ SHELL'
ac_subst_files='' ac_subst_files=''
ac_user_opts=' ac_user_opts='
enable_option_checking enable_option_checking
with_cligen
with_qdbm
enable_keycontent enable_keycontent
' '
ac_precious_vars='build_alias ac_precious_vars='build_alias
@ -1328,6 +1330,12 @@ Optional Features:
--enable-FEATURE[=ARG] include FEATURE [ARG=yes] --enable-FEATURE[=ARG] include FEATURE [ARG=yes]
--disable-keycontent Disable reverse lookup content keys --disable-keycontent Disable reverse lookup content keys
Optional Packages:
--with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
--without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
--with-cligen=dir Use CLIGEN here
--with-qdbm=dir Use QDBM here
Some influential environment variables: Some influential environment variables:
CC C compiler command CC C compiler command
CFLAGS C compiler flags CFLAGS C compiler flags
@ -2165,7 +2173,6 @@ _ACEOF
# Bind to specific CLIgen version # Bind to specific CLIgen version
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: CLIXON version is ${CLIXON_VERSION}_PRE1" >&5 { $as_echo "$as_me:${as_lineno-$LINENO}: result: CLIXON version is ${CLIXON_VERSION}_PRE1" >&5
$as_echo "CLIXON version is ${CLIXON_VERSION}_PRE1" >&6; } $as_echo "CLIXON version is ${CLIXON_VERSION}_PRE1" >&6; }
@ -2322,7 +2329,6 @@ test -n "$target_alias" &&
# Some stuff installed in /usr/local/. Such as qdbm # Some stuff installed in /usr/local/. Such as qdbm
LIBS="-L /usr/local/lib"
# #
ac_ext=c ac_ext=c
@ -3475,14 +3481,9 @@ if test "$YACC" != "bison -y"; then
fi fi
if test "$prefix" = "NONE"; then if test "$prefix" = "NONE"; then
CPPFLAGS="-I${ac_default_prefix}/include ${CPPFLAGS}" prefix=${ac_default_prefix}
LDFLAGS="-L${ac_default_prefix}/lib ${LDFLAGS}"
else
CPPFLAGS="-I${prefix}/include ${CPPFLAGS}"
LDFLAGS="-L${prefix}/lib ${LDFLAGS}"
fi fi
LDFLAGS=""
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lm" >&5 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lm" >&5
$as_echo_n "checking for main in -lm... " >&6; } $as_echo_n "checking for main in -lm... " >&6; }
if ${ac_cv_lib_m_main+:} false; then : if ${ac_cv_lib_m_main+:} false; then :
@ -3528,8 +3529,24 @@ AR_SUFFIX=".a"
SH_SUFFIX=".so" SH_SUFFIX=".so"
AR="ar" AR="ar"
CPPFLAGS="-I${prefix}/include ${CPPFLAGS}"
LDFLAGS="-L${prefix}/lib ${LDFLAGS}"
# This is for cligen # This is for cligen
# Check whether --with-cligen was given.
if test "${with_cligen+set}" = set; then :
withval=$with_cligen;
fi
if test "${with_cligen}"; then
echo "Using CLIGEN here: ${with_cligen}"
CPPFLAGS="-I${with_cligen}/include ${CPPFLAGS}"
LDFLAGS="-L${with_cligen}/lib ${LDFLAGS}"
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5
$as_echo_n "checking for grep that handles long lines and -e... " >&6; } $as_echo_n "checking for grep that handles long lines and -e... " >&6; }
if ${ac_cv_path_GREP+:} false; then : if ${ac_cv_path_GREP+:} false; then :
@ -3854,7 +3871,21 @@ else
fi fi
# This is for qdbm. # This is for qdbm
# Check whether --with-qdbm was given.
if test "${with_qdbm+set}" = set; then :
withval=$with_qdbm;
fi
if test "${with_qdbm}"; then
echo "Using QDBM here: ${with_qdbm}"
CPPFLAGS="-I${with_qdbm}/include ${CPPFLAGS}"
LDFLAGS="-L${with_qdbm}/lib ${LDFLAGS}"
fi
LIBS="${LIBS} ${LDFLAGS}"
# Problem: depot.h may be in qdbm/depot.h. # Problem: depot.h may be in qdbm/depot.h.
for ac_header in depot.h for ac_header in depot.h
do : do :

View file

@ -62,7 +62,6 @@ AC_SUBST(CLIXON_VERSION_MAJOR)
AC_SUBST(CLIXON_VERSION_MINOR) AC_SUBST(CLIXON_VERSION_MINOR)
AC_SUBST(CLIGEN_VERSION) # Bind to specific CLIgen version AC_SUBST(CLIGEN_VERSION) # Bind to specific CLIgen version
AC_MSG_RESULT(CLIXON version is ${CLIXON_VERSION}_PRE1) AC_MSG_RESULT(CLIXON version is ${CLIXON_VERSION}_PRE1)
AC_CANONICAL_TARGET AC_CANONICAL_TARGET
@ -80,7 +79,6 @@ AC_SUBST(AR)
AC_SUBST(RANLIB) AC_SUBST(RANLIB)
# Some stuff installed in /usr/local/. Such as qdbm # Some stuff installed in /usr/local/. Such as qdbm
LIBS="-L /usr/local/lib"
# #
AC_PROG_CC() AC_PROG_CC()
@ -105,14 +103,9 @@ if test "$YACC" != "bison -y"; then
fi fi
if test "$prefix" = "NONE"; then if test "$prefix" = "NONE"; then
CPPFLAGS="-I${ac_default_prefix}/include ${CPPFLAGS}" prefix=${ac_default_prefix}
LDFLAGS="-L${ac_default_prefix}/lib ${LDFLAGS}"
else
CPPFLAGS="-I${prefix}/include ${CPPFLAGS}"
LDFLAGS="-L${prefix}/lib ${LDFLAGS}"
fi fi
LDFLAGS=""
AC_CHECK_LIB(m, main) AC_CHECK_LIB(m, main)
EXE_SUFFIX="" EXE_SUFFIX=""
OBJ_SUFFIX=".o" OBJ_SUFFIX=".o"
@ -120,12 +113,32 @@ AR_SUFFIX=".a"
SH_SUFFIX=".so" SH_SUFFIX=".so"
AR="ar" AR="ar"
CPPFLAGS="-I${prefix}/include ${CPPFLAGS}"
LDFLAGS="-L${prefix}/lib ${LDFLAGS}"
# This is for cligen # This is for cligen
AC_ARG_WITH(cligen, [ --with-cligen=dir Use CLIGEN here ] )
if test "${with_cligen}"; then
echo "Using CLIGEN here: ${with_cligen}"
CPPFLAGS="-I${with_cligen}/include ${CPPFLAGS}"
LDFLAGS="-L${with_cligen}/lib ${LDFLAGS}"
fi
AC_CHECK_HEADERS(cligen/cligen.h,, AC_MSG_ERROR(cligen missing. Try: git clone https://github.com/olofhagsand/cligen.git)) AC_CHECK_HEADERS(cligen/cligen.h,, AC_MSG_ERROR(cligen missing. Try: git clone https://github.com/olofhagsand/cligen.git))
AC_CHECK_LIB(:libcligen.so.${CLIGEN_VERSION}, cligen_init,, AC_MSG_ERROR([CLIgen${CLIGEN_VERSION} missing. Try: git clone https://github.com/olofhagsand/cligen.git])) AC_CHECK_LIB(:libcligen.so.${CLIGEN_VERSION}, cligen_init,, AC_MSG_ERROR([CLIgen${CLIGEN_VERSION} missing. Try: git clone https://github.com/olofhagsand/cligen.git]))
# This is for qdbm. # This is for qdbm
AC_ARG_WITH(qdbm, [ --with-qdbm=dir Use QDBM here ] )
if test "${with_qdbm}"; then
echo "Using QDBM here: ${with_qdbm}"
CPPFLAGS="-I${with_qdbm}/include ${CPPFLAGS}"
LDFLAGS="-L${with_qdbm}/lib ${LDFLAGS}"
fi
LIBS="${LIBS} ${LDFLAGS}"
# Problem: depot.h may be in qdbm/depot.h. # Problem: depot.h may be in qdbm/depot.h.
AC_CHECK_HEADERS(depot.h,,[AC_CHECK_HEADERS(qdbm/depot.h,,AC_MSG_ERROR(libqdbm-dev required))]) AC_CHECK_HEADERS(depot.h,,[AC_CHECK_HEADERS(qdbm/depot.h,,AC_MSG_ERROR(libqdbm-dev required))])
AC_CHECK_LIB(qdbm, dpopen,, AC_MSG_ERROR(libqdbm-dev required)) AC_CHECK_LIB(qdbm, dpopen,, AC_MSG_ERROR(libqdbm-dev required))

View file

@ -432,7 +432,10 @@ clicon_rpc(int s,
case CLICON_MSG_ERR: case CLICON_MSG_ERR:
if (clicon_msg_err_decode(reply, &err, &suberr, &reason, label) < 0) if (clicon_msg_err_decode(reply, &err, &suberr, &reason, label) < 0)
goto done; goto done;
clicon_err(err, suberr, "%s msgtype:%hu", reason, ntohs(msg->op_type)); if (debug)
clicon_err(err, suberr, "%s msgtype:%hu", reason, ntohs(msg->op_type));
else
clicon_err(err, suberr, "%s", reason);
goto done; goto done;
break; break;
default: default:

View file

@ -288,7 +288,7 @@ xml_yang_validate(cxobj *xt,
{ {
int retval = -1; int retval = -1;
cg_var *cv = NULL; cg_var *cv = NULL;
char *reason; char *reason = NULL;
yang_stmt *yc; yang_stmt *yc;
int i; int i;
yang_stmt *ys; yang_stmt *ys;
@ -318,6 +318,9 @@ xml_yang_validate(cxobj *xt,
clicon_err(OE_UNIX, errno, "cv_dup"); clicon_err(OE_UNIX, errno, "cv_dup");
goto done; goto done;
} }
/* In the union case, value is parsed as generic REST type,
* needs to be reparsed when concrete type is selected
*/
if (cv_parse(xml_body(xt), cv) <0){ if (cv_parse(xml_body(xt), cv) <0){
clicon_err(OE_UNIX, errno, "cv_parse"); clicon_err(OE_UNIX, errno, "cv_parse");
goto done; goto done;

View file

@ -377,59 +377,32 @@ clicon_type2cv(char *origtype, char *restype, enum cv_type *cvtype)
(rmax && (i) > cv_##type##_get(rmax))) (rmax && (i) > cv_##type##_get(rmax)))
/*! Validate cligen variable cv using yang statement as spec /*!
*
* @param [in] cv A cligen variable to validate. This is a correctly parsed cv.
* @param [in] ys A yang statement, must be leaf of leaf-list.
* @param [out] reason If given, and if return value is 0, contains a malloced string
* describing the reason why the validation failed. Must be freed.
* @retval -1 Error (fatal), with errno set to indicate error * @retval -1 Error (fatal), with errno set to indicate error
* @retval 0 Validation not OK, malloced reason is returned. Free reason with free() * @retval 0 Validation not OK, malloced reason is returned. Free reason with free()
* @retval 1 Validation OK * @retval 1 Validation OK
* See also cv_validate - the code is similar.
*/ */
int static int
ys_cv_validate(cg_var *cv, yang_stmt *ys, char **reason) cv_validate1(cg_var *cv,
enum cv_type cvtype,
int options,
cg_var *range_min,
cg_var *range_max,
char *pattern,
yang_stmt *yrestype,
char *restype,
char **reason)
{ {
int retval = 1; /* OK */ int retval = 1; /* OK */
cg_var *ycv; /* cv of yang-statement */
int64_t i = 0;
uint64_t u = 0;
char *str;
int options;
cg_var *range_min;
cg_var *range_max;
char *pattern;
int retval2; int retval2;
enum cv_type cvtype;
char *type; /* orig type */
yang_stmt *yrestype; /* resolved type */
char *restype;
uint8_t fraction;
yang_stmt *yi = NULL; yang_stmt *yi = NULL;
uint64_t u = 0;
int64_t i = 0;
char *str;
if (reason) if (reason && *reason){
free(*reason);
*reason = NULL; *reason = NULL;
if (ys->ys_keyword != Y_LEAF && ys->ys_keyword != Y_LEAF_LIST)
return 0;
ycv = ys->ys_cv;
if (yang_type_get(ys, &type, &yrestype,
&options, &range_min, &range_max, &pattern,
&fraction) < 0)
goto err;
restype = yrestype?yrestype->ys_argument:NULL;
if (clicon_type2cv(type, restype, &cvtype) < 0)
goto err;
if (cv_type_get(ycv) != cvtype){
/* special case: dbkey has rest syntax-> cv but yang cant have that */
if (cvtype == CGV_STRING && cv_type_get(ycv) == CGV_REST)
;
else {
clicon_err(OE_DB, 0, "%s: Type mismatch data:%s != yang:%s",
__FUNCTION__, cv_type2str(cvtype), cv_type2str(cv_type_get(ycv)));
goto err;
}
} }
switch (cvtype){ switch (cvtype){
case CGV_INT8: case CGV_INT8:
@ -597,10 +570,112 @@ ys_cv_validate(cg_var *cv, yang_stmt *ys, char **reason)
} }
if (reason && *reason) if (reason && *reason)
assert(retval == 0); assert(retval == 0); /* validation failed with error reason */
return retval;
}
/*! Validate cligen variable cv using yang statement as spec
*
* @param[in] cv A cligen variable to validate. This is a correctly parsed cv.
* @param[in] ys A yang statement, must be leaf of leaf-list.
* @param[out] reason If given, and if return value is 0, contains a malloced string
* describing the reason why the validation failed. Must be freed.
* @retval -1 Error (fatal), with errno set to indicate error
* @retval 0 Validation not OK, malloced reason is returned. Free reason with free()
* @retval 1 Validation OK
* See also cv_validate - the code is similar.
*/
int
ys_cv_validate(cg_var *cv,
yang_stmt *ys,
char **reason)
{
int retval = -1;
cg_var *ycv; /* cv of yang-statement */
int options;
cg_var *range_min;
cg_var *range_max;
char *pattern;
enum cv_type cvtype;
char *type; /* orig type */
yang_stmt *yrestype; /* resolved type */
yang_stmt *yrt; /* union subtype */
char *restype;
uint8_t fraction;
yang_stmt *yt = NULL;
int retval2;
char *val;
cg_var *cvt=NULL;
if (reason)
*reason=NULL;
if (ys->ys_keyword != Y_LEAF && ys->ys_keyword != Y_LEAF_LIST){
retval = 1;
goto done;
}
ycv = ys->ys_cv;
if (yang_type_get(ys, &type, &yrestype,
&options, &range_min, &range_max, &pattern,
&fraction) < 0)
goto done;
restype = yrestype?yrestype->ys_argument:NULL;
if (clicon_type2cv(type, restype, &cvtype) < 0)
goto done;
if (cv_type_get(ycv) != cvtype){
/* special case: dbkey has rest syntax-> cv but yang cant have that */
if (cvtype == CGV_STRING && cv_type_get(ycv) == CGV_REST)
;
else {
clicon_err(OE_DB, 0, "%s: Type mismatch data:%s != yang:%s",
__FUNCTION__, cv_type2str(cvtype), cv_type2str(cv_type_get(ycv)));
goto done;
}
}
/* Note restype can be NULL here for example with unresolved hardcoded uuid */
if (restype && strcmp(restype, "union") == 0){
yt = NULL;
retval2 = 1; /* valid */
assert(cvtype == CGV_REST);
val = cv_string_get(cv);
while ((yt = yn_each((yang_node*)yrestype, yt)) != NULL){
if (yt->ys_keyword != Y_TYPE)
continue;
if (yang_type_resolve(ys, yt, &yrt,
&options, &range_min, &range_max, &pattern,
&fraction) < 0)
goto done;
restype = yrestype?yrt->ys_argument:NULL;
if (clicon_type2cv(type, restype, &cvtype) < 0)
goto done;
/* reparse value with the new type */
if ((cvt = cv_new(cvtype)) == NULL){
clicon_err(OE_UNIX, errno, "cv_new");
goto done;
}
if (cv_parse(val, cvt) <0){
clicon_err(OE_UNIX, errno, "cv_parse");
goto done;
}
if ((retval2 = cv_validate1(cvt, cvtype, options, range_min, range_max,
pattern, yrt, restype, reason)) < 0)
goto done;
if (retval2 == 1) /* done */
break;
/* Here retval == 0, validation failed */
cv_free(cvt);
cvt=NULL;
}
retval = retval2; /* invalid (0) with latest reason or valid 1 */
}
else
if ((retval = cv_validate1(cv, cvtype, options, range_min, range_max, pattern,
yrestype, restype, reason)) < 0)
goto done;
done:
if (cvt)
cv_free(cvt);
return retval; return retval;
err:
return -1;
} }
/* /*