C-style update: Unified comment, retvals in order, remove trailing spaces

Changed function name for `clicon_debug` functions
This commit is contained in:
Olof hagsand 2023-10-22 18:04:47 +02:00
parent 6e314dd96f
commit 62348fc9c7
204 changed files with 6047 additions and 4904 deletions

View file

@ -50,17 +50,17 @@ typedef enum {
* see https://clixon-docs.readthedocs.io/en/latest/netconf.html#ipc
* Must be local on device
*/
CLIXON_CLIENT_IPC,
CLIXON_CLIENT_IPC,
/* Regular NETCONF via local netconf binary
* Fork clixon_netconf locally which in turn communicates with backend
* Must be local on device
*/
CLIXON_CLIENT_NETCONF,
CLIXON_CLIENT_NETCONF,
/* Regular NETCONF using ssh sub-system via local SSH (openssh) client binary
* Fork ssh locally which in turn communicates remotely to device
* Must have openssh installed locally and device must have ssh sub-subsystem
*/
CLIXON_CLIENT_SSH
CLIXON_CLIENT_SSH
} clixon_client_type;
/*
@ -70,7 +70,7 @@ typedef enum {
#ifdef __cplusplus
extern "C" {
#endif
clixon_handle clixon_client_init(const char *config_file);
int clixon_client_terminate(clixon_handle h);
int clixon_client_lock(int sock, const char *descr, const int lock, const char *db);
@ -83,7 +83,7 @@ int clixon_client_get_uint8(clixon_client_handle ch, uint8_t *rval, const char
int clixon_client_get_uint16(clixon_client_handle ch, uint16_t *rval, const char *xnamespace, const char *xpath);
int clixon_client_get_uint32(clixon_client_handle ch, uint32_t *rval, const char *xnamespace, const char *xpath);
int clixon_client_get_uint64(clixon_client_handle ch, uint64_t *rval, const char *xnamespace, const char *xpath);
/* Access functions */
int clixon_client_socket_get(clixon_client_handle ch);

View file

@ -125,19 +125,19 @@ int clicon_socket_set(clicon_handle h, int s);
int clicon_client_socket_get(clicon_handle h);
int clicon_client_socket_set(clicon_handle h, int s);
/*! Set and get module state full and brief cached tree */
/* Set and get module state full and brief cached tree */
cxobj *clicon_modst_cache_get(clicon_handle h, int brief);
int clicon_modst_cache_set(clicon_handle h, int brief, cxobj *xms);
/*! Set and get yang/xml module revision changelog */
/* Set and get yang/xml module revision changelog */
cxobj *clicon_xml_changelog_get(clicon_handle h);
int clicon_xml_changelog_set(clicon_handle h, cxobj *xchlog);
/*! Set and get user command-line options (after --) */
/* Set and get user command-line options (after --) */
int clicon_argv_get(clicon_handle h, int *argc, char ***argv);
int clicon_argv_set(clicon_handle h, char *argv0, int argc, char **argv);
/*! Set and get (client/backend) session id */
/* Set and get (client/backend) session id */
int clicon_session_id_set(clicon_handle h, uint32_t id);
int clicon_session_id_get(clicon_handle h, uint32_t *id);
int clicon_session_id_del(clicon_handle h);

View file

@ -52,7 +52,7 @@ int xmldb_disconnect(clicon_handle h);
int xmldb_get(clicon_handle h, const char *db, cvec *nsc, char *xpath, cxobj **xtop);
int xmldb_get0(clicon_handle h, const char *db, yang_bind yb,
cvec *nsc, const char *xpath, int copy, withdefaults_type wdef,
cxobj **xtop, modstate_diff_t *msd, cxobj **xerr);
cxobj **xtop, modstate_diff_t *msd, cxobj **xerr);
int xmldb_get0_clear(clicon_handle h, cxobj *x);
int xmldb_get0_free(clicon_handle h, cxobj **xp);
int xmldb_put(clicon_handle h, const char *db, enum operation_type op, cxobj *xt, char *username, cbuf *cbret); /* in clixon_datastore_write.[ch] */

View file

@ -38,6 +38,7 @@
#define _CLIXON_DISPATCH_DISPATCHER_H
/*! Prototype for a function to handle a path
*
* minimally needs the path it's working on, but probably
* we want to hand down cached data somehow
* @param[in] h Generic handler

View file

@ -45,7 +45,7 @@
/*
* Constants
*/
*/
#define ERR_STRLEN 256
/* Special error number for clicon_suberrno
@ -57,9 +57,9 @@
* Types
* Add error category here,
* @see EV variable in clixon_err.c but must also add an entry there
*/
*/
enum clicon_err{
/* 0 means error not set) */
/* 0 means error not set) */
OE_DB = 1, /* database registries */
OE_DAEMON, /* daemons: pidfiles, etc */
OE_EVENTS, /* events, filedescriptors, timeouts */
@ -79,11 +79,12 @@ enum clicon_err{
OE_UNDEF,
/*-- From here error extensions using clixon_err_cat_reg, XXX register dynamically? --*/
OE_SSL, /* Openssl errors, see eg ssl_get_error and clixon_openssl_log_cb */
OE_SNMP , /* Netsnmp error */
OE_SNMP , /* Netsnmp error */
OE_NGHTTP2, /* nghttp2 errors, see HAVE_LIBNGHTTP2 */
};
/* Clixon error category log callback
/*! Clixon error category log callback
*
* @param[in] handle Application-specific handle
* @param[in] suberr Application-specific handle
* @param[out] cb Read log/error string into this buffer

View file

@ -59,7 +59,7 @@ int clixon_event_reg_fd(int fd, int (*fn)(int, void*), void *arg, char *str);
int clixon_event_unreg_fd(int s, int (*fn)(int, void*));
int clixon_event_reg_timeout(struct timeval t, int (*fn)(int, void*),
int clixon_event_reg_timeout(struct timeval t, int (*fn)(int, void*),
void *arg, char *str);
int clixon_event_unreg_timeout(int (*fn)(int, void*), void *arg);

View file

@ -40,7 +40,7 @@
#define _CLIXON_FILE_H_
int clicon_file_dirent(const char *dir, struct dirent **ent,
int clicon_file_dirent(const char *dir, struct dirent **ent,
const char *regexp, mode_t type);
int clicon_files_recursive(const char *dir, const char *regexp, cvec *cvv);
int clicon_file_copy(char *src, char *target);

View file

@ -60,7 +60,7 @@ typedef void *plghndl_t;
*/
typedef int (clicon_output_cb)(
FILE *f,
const char *templ, ...
const char *templ, ...
) __attribute__ ((format (printf, 2, 3)));
/*

View file

@ -67,10 +67,15 @@ size_t clicon_log_string_limit_get(void);
int clicon_get_logflags(void);
int clicon_log_str(int level, char *msg);
int clicon_log(int level, const char *format, ...) __attribute__ ((format (printf, 2, 3)));
int clicon_debug(int dbglevel, const char *format, ...) __attribute__ ((format (printf, 2, 3)));
int clicon_debug_init(int dbglevel, FILE *f);
int clicon_debug_get(void);
int clixon_debug(int dbglevel, const char *format, ...) __attribute__ ((format (printf, 2, 3)));
int clixon_debug_init(int dbglevel, FILE *f);
int clixon_debug_get(void);
char *mon2name(int md);
/* 6.4 backward compatability */
#if 1
#define clicon_debug clixon_debug
#define clicon_debug_init clixon_debug_init
#define clicon_debug_get clixon_debug_get
#endif
#endif /* _CLIXON_LOG_H_ */

View file

@ -49,7 +49,7 @@ extern "C" {
#endif
ssize_t netconf_input_read2(int s, unsigned char *buf, ssize_t buflen, int *eof);
int netconf_input_msg2(unsigned char **bufp, size_t *lenp, cbuf *cbmsg,
int netconf_input_msg2(unsigned char **bufp, size_t *lenp, cbuf *cbmsg,
netconf_framing_type framing, int *frame_state, size_t *frame_size,
int *eom);
int netconf_input_frame2(cbuf *cb, yang_bind yb, yang_stmt *yspec, cxobj **xrecv, cxobj **xerr);

View file

@ -97,7 +97,8 @@
/*
* Types
*/
/*! Content query parameter RFC 8040 Sec 4.8.1
/*! Content query parameter RFC 8040 Sec 4.8.1
*
* Clixon extention: content so that RFC8040 content attribute can be conveyed
* internally used in <get>
*/
@ -111,7 +112,7 @@ typedef enum netconf_content netconf_content;
enum target_type{ /* netconf */
RUNNING,
CANDIDATE
};
};
enum test_option{ /* edit-config */
SET,
@ -126,7 +127,7 @@ enum error_option{ /* edit-config */
/* NETCONF framing
*/
enum framing_type{
enum framing_type{
NETCONF_SSH_EOM=0, /* RFC 4742, RFC 6242 hello msg (end-of-msg: ]]>]]>)*/
NETCONF_SSH_CHUNKED, /* RFC 6242 Chunked framing */
};
@ -135,7 +136,7 @@ typedef enum framing_type netconf_framing_type;
/* NETCONF with-defaults
* @see RFC 6243
*/
enum withdefaults_type{
enum withdefaults_type{
WITHDEFAULTS_REPORT_ALL = 0, /* default behavior: <= Clixon 6.0 */
WITHDEFAULTS_TRIM,
WITHDEFAULTS_EXPLICIT, /* default behavior: > Clixon 6.0 */
@ -147,6 +148,7 @@ typedef enum withdefaults_type withdefaults_type;
* Macros
*/
/*! Generate textual error log from Netconf error message
*
* @param[in] xerr Netconf error xml tree on the form: <rpc-error>
* @param[in] format Format string
* @param[in] arg String argument to format (optional)

View file

@ -46,6 +46,7 @@
* Constants
*/
/*! Clixon configuration namespace
*
* Probably should be defined somewhere else or extracted from yang
* @see clixon-config.yang
* @see clixon-lib.yang
@ -85,6 +86,7 @@ enum nacm_credentials_t{
};
/*! Datastore cache behaviour, see clixon_datastore.[ch]
*
* See config option type datastore_cache in clixon-config.yang
*/
enum datastore_cache{
@ -94,6 +96,7 @@ enum datastore_cache{
};
/*! yang clixon regexp engine
*
* @see regexp_mode in clixon-config.yang
*/
enum regexp_mode{

View file

@ -65,7 +65,7 @@ typedef struct {
qelem_t cp_qelem; /* List header */
char *cp_prefix; /* Prefix or module name, should be resolved + id to cp_yang */
char *cp_id; /* Identifier */
cvec *cp_cvk; /* Key values: list of (name:value) pairs alt (NULL:value)
cvec *cp_cvk; /* Key values: list of (name:value) pairs alt (NULL:value)
* Can also be single uint32, if so positional eg x/y[42]
* This seems kludgy but follows RFC 7950 Sec 9.13
*/
@ -81,7 +81,7 @@ int yang2api_path_fmt(yang_stmt *ys, int inclkey, char **api_path_fmt);
int api_path_fmt2api_path(const char *api_path_fmt, cvec *cvv, char **api_path, int *cvvi);
int api_path_fmt2xpath(char *api_path_fmt, cvec *cvv, char **xpath);
int api_path2xpath(char *api_path, yang_stmt *yspec, char **xpath, cvec **nsc, cxobj **xerr);
int api_path2xml(char *api_path, yang_stmt *yspec, cxobj *xtop,
int api_path2xml(char *api_path, yang_stmt *yspec, cxobj *xtop,
yang_class nodeclass, int strict,
cxobj **xpathp, yang_stmt **ypathp, cxobj **xerr);
int xml2api_path_1(cxobj *x, cbuf *cb);

View file

@ -50,7 +50,7 @@
/*
* Types
*/
/*! Registered RPC callback function
*
* @param[in] h Clicon handle
@ -62,11 +62,11 @@
* @retval -1 Error
*/
typedef int (*clicon_rpc_cb)(
clicon_handle h,
cxobj *xn,
cbuf *cbret,
void *arg,
void *regarg
clicon_handle h,
cxobj *xn,
cbuf *cbret,
void *arg,
void *regarg
);
/*! Registered Upgrade callback function
@ -84,22 +84,22 @@ typedef int (*clicon_rpc_cb)(
* @retval -1 Error
*/
typedef int (*clicon_upgrade_cb)(
clicon_handle h,
cxobj *xn,
clicon_handle h,
cxobj *xn,
char *ns,
uint16_t op,
uint32_t from,
uint32_t to,
void *arg,
void *arg,
cbuf *cbret
);
);
/* Clixon authentication type
* @see http-auth-type in clixon-restconf.yang
* For now only used by restconf frontend
*/
enum clixon_auth_type {
CLIXON_AUTH_NONE = 0, /* Message is authenticated automatically to
CLIXON_AUTH_NONE = 0, /* Message is authenticated automatically to
anonymous user, maye be changed by ca-auth callback
FEATURE clixon-restconf:allow-auth-none must be enabled */
CLIXON_AUTH_CLIENT_CERTIFICATE, /* TLS Client certification authentication */
@ -108,13 +108,15 @@ enum clixon_auth_type {
};
typedef enum clixon_auth_type clixon_auth_type_t;
/* Common plugin function names, function types and signatures.
/*! Common plugin function names, function types and signatures.
*
* This plugin code is exytended by backend, cli, netconf, restconf plugins
* Cli see cli_plugin.c
* Backend see config_plugin.c
*/
/* Called when application is "started", (almost) all initialization is complete
/*! Called when application is "started", (almost) all initialization is complete
*
* Backend: daemon is in the background. If daemon privileges are dropped
* this callback is called *before* privileges are dropped.
* @param[in] h Clixon handle
@ -203,7 +205,7 @@ typedef int (plgauth_t)(clicon_handle h, void *req, clixon_auth_type_t auth_type
* @retval 0 OK
* @retval -1 Fatal error
*/
typedef int (plgreset_t)(clicon_handle h, const char *db);
typedef int (plgreset_t)(clicon_handle h, const char *db);
/* Provide state data from plugin
*
@ -215,7 +217,7 @@ typedef int (plgreset_t)(clicon_handle h, const char *db);
*
* @param[in] h Clicon handle
* @param[in] xpath Part of state requested
* @param[in] nsc XPATH namespace context.
* @param[in] nsc XPath namespace context.
* @param[out] xtop XML tree where statedata is added
* @retval 0 OK
* @retval -1 Fatal error
@ -226,7 +228,8 @@ typedef int (plgreset_t)(clicon_handle h, const char *db);
*/
typedef int (plgstatedata_t)(clicon_handle h, cvec *nsc, char *xpath, cxobj *xtop);
/* Pagination-data type
/*! Pagination-data type
*
* @see pagination_data_t in for full pagination data structure
* @see pagination_offset() and other accessor functions
*/
@ -243,7 +246,8 @@ typedef void *pagination_data;
*/
typedef int (plglockdb_t)(clicon_handle h, char *db, int lock, int id);
/* Transaction-data type
/*! Transaction-data type
*
* @see transaction_data_t and clixon_backend_transaction.h for full transaction API
*/
typedef void *transaction_data;
@ -252,6 +256,7 @@ typedef void *transaction_data;
typedef int (trans_cb_t)(clicon_handle h, transaction_data td);
/*! Hook to override default prompt with explicit function
*
* Format prompt before each getline
* @param[in] h Clicon handle
* @param[in] mode Cligen syntax mode
@ -311,6 +316,7 @@ typedef int (yang_mount_t)(clicon_handle h, cxobj *xt, int *config,
typedef int (yang_patch_t)(clicon_handle h, yang_stmt *ymod);
/*! Startup status for use in startup-callback
*
* Note that for STARTUP_ERR and STARTUP_INVALID, running runs in failsafe mode
* and startup contains the erroneous or invalid database.
* The user should repair the startup and
@ -400,6 +406,7 @@ typedef struct clixon_plugin_api clixon_plugin_api;
typedef struct clixon_plugin clixon_plugin_t;
/*! Structure for checking status before and after a plugin call
*
* The internal struct is defined in clixon_plugin.c */
typedef struct plugin_context plugin_context_t;

View file

@ -40,7 +40,7 @@
/*
* Types
*/
*/
typedef struct process_entry_t process_entry_t;
/* Process operations */
@ -52,7 +52,7 @@ typedef enum proc_operation {
PROC_OP_STATUS
} proc_operation;
/*! Process RPC callback function
/*! Process RPC callback function
*
* @param[in] h Clixon handle
* @param[in] pe Process entry
@ -64,7 +64,7 @@ typedef int (proc_cb_t)(clicon_handle h,
/*
* Prototypes
*/
*/
int clixon_proc_socket(char **argv, int sock_flags, pid_t *pid, int *sock);
int clixon_proc_socket_close(pid_t pid, int sock);
int clixon_process_pid(clicon_handle h, const char *name, pid_t *pid);

View file

@ -53,7 +53,7 @@ struct clicon_msg {
/*
* Prototypes
*/
*/
char *format_int2str(enum format_enum showas);
enum format_enum format_str2int(char *str);
@ -68,7 +68,7 @@ int clicon_rpc_connect_unix(clicon_handle h,
int *sock0);
int clicon_rpc_connect_inet(clicon_handle h,
char *dst,
char *dst,
uint16_t port,
int *sock0);

View file

@ -48,7 +48,7 @@ int clicon_rpc_msg_persistent(clicon_handle h, struct clicon_msg *msg, cxobj **x
int clicon_rpc_netconf(clicon_handle h, char *xmlst, cxobj **xret, int *sp);
int clicon_rpc_netconf_xml(clicon_handle h, cxobj *xml, cxobj **xret, int *sp);
int clicon_rpc_get_config(clicon_handle h, char *username, char *db, char *xpath, cvec *nsc, char *defaults, cxobj **xret);
int clicon_rpc_edit_config(clicon_handle h, char *db, enum operation_type op,
int clicon_rpc_edit_config(clicon_handle h, char *db, enum operation_type op,
char *xml);
int clicon_rpc_copy_config(clicon_handle h, char *db1, char *db2);
int clicon_rpc_delete_config(clicon_handle h, char *db);
@ -56,7 +56,7 @@ int clicon_rpc_lock(clicon_handle h, char *db);
int clicon_rpc_unlock(clicon_handle h, char *db);
int clicon_rpc_get2(clicon_handle h, char *xpath, cvec *nsc, netconf_content content, int32_t depth, char *defaults, int bind, cxobj **xret);
int clicon_rpc_get(clicon_handle h, char *xpath, cvec *nsc, netconf_content content, int32_t depth, char *defaults, cxobj **xret);
int clicon_rpc_get_pageable_list(clicon_handle h, char *datastore, char *xpath,
int clicon_rpc_get_pageable_list(clicon_handle h, char *datastore, char *xpath,
cvec *nsc, netconf_content content, int32_t depth, char *defaults,
uint32_t offset, uint32_t limit,
char *direction, char *sort, char *where,

View file

@ -40,6 +40,7 @@
#define _CLIXON_QUEUE_H_
/*! Circular queue structure for use as first entry in a parent structure.
*
* Add qelem_t as first element in struct
* @code
* struct a{
@ -55,6 +56,7 @@ typedef struct _qelem_t {
} qelem_t;
/*! Append element 'elem' to queue.
*
* @param[in] elem Element to be added
* @param[in,out] pred Add element after this
* @code
@ -78,6 +80,7 @@ typedef struct _qelem_t {
}
/*! Insert element 'elem' in queue after 'pred'
*
* @param[in] elem Element to be added
* @param[in,out] pred Add element after this
* @code
@ -100,7 +103,8 @@ typedef struct _qelem_t {
pred = elem; \
}
/*! Remove element 'elem' from queue. 'head' is the pointer to the queue and
/*! Remove element 'elem' from queue. 'head' is the pointer to the queue and
*
* is of 'type'.
* @param[in] elem
* @param[in] head
@ -121,6 +125,7 @@ typedef struct _qelem_t {
}
/*! Get next entry in list
*
* @param[in] type Type of element
* @param[in] el Return next element after elem.
* @code

View file

@ -40,7 +40,7 @@
/*
* Prototypes
*/
*/
int regexp_xsd2posix(char *xsd, char **posix);
int regex_compile(clicon_handle h, char *regexp, void **recomp);
int regex_exec(clicon_handle h, void *recomp, char *string);

View file

@ -45,7 +45,7 @@ typedef void (*sigfn_t)(int);
/*
* Prototypes
*/
*/
int set_signal(int signo, void (*handler)(int), void (**oldhandler)(int));
int set_signal_flags(int signo, int flags, void (*handler)(int), void (**oldhandler)(int));
int clixon_signal_save(sigset_t *sigset, struct sigaction sigaction_vec[32]);

View file

@ -45,7 +45,8 @@
/*
* Types
*/
/* Subscription callback
/*! Subscription callback
*
* @param[in] h Clicon handle
* @param[in] op Operation: 0 OK, 1 Close
* @param[in] event Event as XML

View file

@ -39,12 +39,13 @@
#define _CLIXON_STRING_H_
/*! Struct used to map between int and strings. Typically used to map between
*
* values and their names. Note NULL terminated
* Example:
* @code
static const map_str2int atmap[] = {
{"One", 1},
{"Two", 2},
{"One", 1},
{"Two", 2},
{NULL, -1}
};
* @endcode
@ -73,7 +74,7 @@ typedef struct map_str2str map_str2str;
#include <string.h>
/*! A strdup version that aligns on 4 bytes. To avoid warning from valgrind */
static inline char * strdup4(char *str)
static inline char * strdup4(char *str)
{
char *dup;
size_t len;
@ -86,7 +87,7 @@ static inline char * strdup4(char *str)
/*
* Prototypes
*/
*/
char **clicon_strsep(char *string, char *delim, int *nvec0);
char *clicon_strjoin (int argc, char **argv, char *delim);
char *clixon_string_del_join(char *str1, char *del, char *str2);

View file

@ -41,7 +41,7 @@
/*
* Prototypes
*/
*/
int group_name2gid(const char *name, gid_t *gid);
int name2uid(const char *name, uid_t *uid);
int uid2name(const uid_t uid, char **name);

View file

@ -85,7 +85,7 @@
* This is a "neutral" symbol without any meaning as opposed to the previous symbols ^
* @see DATASTORE_TOP_SYMBOL which should be used for clixon top-level config trees
*/
#define XML_TOP_SYMBOL "top"
#define XML_TOP_SYMBOL "top"
/*
* Types
@ -102,16 +102,16 @@ enum operation_type{ /* edit-config operation */
/* Netconf insert type (see RFC7950 Sec 7.8.6) */
enum insert_type{ /* edit-config insert */
INS_FIRST,
INS_LAST,
INS_BEFORE,
INS_AFTER,
INS_FIRST,
INS_LAST,
INS_BEFORE,
INS_AFTER,
};
/* XML object types */
enum cxobj_type {CX_ERROR=-1,
CX_ELMNT,
CX_ATTR,
enum cxobj_type {CX_ERROR=-1,
CX_ELMNT,
CX_ATTR,
CX_BODY};
/* How to bind yang to XML top-level when parsing
@ -145,7 +145,7 @@ enum cxobj_type {CX_ERROR=-1,
* / \ / \
* x1 x2 - - y1 y2
*/
enum yang_bind{
enum yang_bind{
YB_NONE=0, /* Dont do Yang binding */
YB_MODULE, /* Search for matching yang binding among top-level symbols of Yang modules of direct
* children
@ -165,7 +165,7 @@ typedef enum yang_bind yang_bind;
typedef struct xml cxobj; /* struct defined in clicon_xml.c */
/*! Callback function type for xml_apply
/*! Callback function type for xml_apply
*
* @param[in] x XML node
* @param[in] arg General-purpose argument
@ -182,9 +182,9 @@ typedef struct clixon_xml_vec clixon_xvec; /* struct defined in clicon_xml_vec.c
* @see format_int2str, format_str2int
*/
enum format_enum{
FORMAT_XML,
FORMAT_JSON,
FORMAT_TEXT,
FORMAT_XML,
FORMAT_JSON,
FORMAT_TEXT,
FORMAT_CLI,
FORMAT_NETCONF
};
@ -304,7 +304,7 @@ char *xml_operation2str(enum operation_type op);
int xml_attr_insert2val(char *instr, enum insert_type *ins);
int xml_add_attr(cxobj *xn, char *name, char *value, char *prefix, char *ns);
int clicon_log_xml(int level, cxobj *x, const char *format, ...) __attribute__ ((format (printf, 3, 4)));
int clicon_debug_xml(int dbglevel, cxobj *x, const char *format, ...) __attribute__ ((format (printf, 3, 4)));
int clixon_debug_xml(int dbglevel, cxobj *x, const char *format, ...) __attribute__ ((format (printf, 3, 4)));
#ifdef XML_EXPLICIT_INDEX
int xml_search_index_p(cxobj *x);

View file

@ -50,7 +50,7 @@ int clixon_xml2cbuf(cbuf *cb, cxobj *x, int level, int prettyprint, char *pref
int xmltree2cbuf(cbuf *cb, cxobj *x, int level);
int clixon_xml_parse_file(FILE *f, yang_bind yb, yang_stmt *yspec, cxobj **xt, cxobj **xerr);
int clixon_xml_parse_string(const char *str, yang_bind yb, yang_stmt *yspec, cxobj **xt, cxobj **xerr);
int clixon_xml_parse_va(yang_bind yb, yang_stmt *yspec, cxobj **xt, cxobj **xerr,
int clixon_xml_parse_va(yang_bind yb, yang_stmt *yspec, cxobj **xt, cxobj **xerr,
const char *format, ...) __attribute__ ((format (printf, 5, 6)));
int clixon_xml_attr_copy(cxobj *xin, cxobj *xout, char *name);
int clixon_xml_diff2cbuf(cbuf *cb, cxobj *x0, cxobj *x1);

View file

@ -53,9 +53,9 @@ int isxmlns(cxobj *x);
int xmlns_assign(cxobj *x);
int xml2cvec(cxobj *xt, yang_stmt *ys, cvec **cvv0);
int cvec2xml_1(cvec *cvv, char *toptag, cxobj *xp, cxobj **xt0);
int xml_diff(cxobj *x0, cxobj *x1,
cxobj ***first, int *firstlen,
cxobj ***second, int *secondlen,
int xml_diff(cxobj *x0, cxobj *x1,
cxobj ***first, int *firstlen,
cxobj ***second, int *secondlen,
cxobj ***changed_x0, cxobj ***changed_x1, int *changedlen);
int xml_tree_equal(cxobj *x0, cxobj *x1);
int xml_tree_prune_flagged_sub(cxobj *xt, int flag, int test, int *upmark);

View file

@ -32,7 +32,7 @@
***** END LICENSE BLOCK *****
* Clixon XML XPATH 1.0 according to https://www.w3.org/TR/xpath-10
* Clixon XML XPath 1.0 according to https://www.w3.org/TR/xpath-10
*/
#ifndef _CLIXON_XPATH_H
#define _CLIXON_XPATH_H
@ -66,10 +66,10 @@ enum axis_type{
A_ANCESTOR_OR_SELF,
A_ATTRIBUTE,
A_CHILD,
A_DESCENDANT,
A_DESCENDANT,
A_DESCENDANT_OR_SELF,
A_FOLLOWING,
A_FOLLOWING_SIBLING,
A_FOLLOWING_SIBLING,
A_NAMESPACE,
A_PARENT,
A_PRECEDING,
@ -103,9 +103,10 @@ enum xp_type{
};
/*! XPATH Parsing generates a tree of nodes that is later traversed
* That is, a tree-structured XPATH.
* Note that the structure follows XPATH 1.0 closely. The drawback wit this is that the tree gets
* very deep very quickly, even for simple XPATHs.
*
* That is, a tree-structured XPath.
* Note that the structure follows XPath 1.0 closely. The drawback wit this is that the tree gets
* very deep very quickly, even for simple XPaths.
*/
struct xpath_tree{
enum xp_type xs_type;
@ -136,7 +137,7 @@ int xpath_parse(const char *xpath, xpath_tree **xptree);
int xpath_vec_ctx(cxobj *xcur, cvec *nsc, const char *xpath, int localonly, xp_ctx **xrp);
int xpath_vec_bool(cxobj *xcur, cvec *nsc, const char *xpformat, ...) __attribute__ ((format (printf, 3, 4)));
int xpath_vec_flag(cxobj *xcur, cvec *nsc, const char *xpformat, uint16_t flags,
int xpath_vec_flag(cxobj *xcur, cvec *nsc, const char *xpformat, uint16_t flags,
cxobj ***vec, size_t *veclen, ...) __attribute__ ((format (printf, 3, 7)));
/* Functions with explicit namespace context (nsc) set. If you do not need

View file

@ -33,8 +33,8 @@
***** END LICENSE BLOCK *****
* Clixon XML XPATH 1.0 according to https://www.w3.org/TR/xpath-10
* This file defines XPATH contexts using in traversing the XPATH parse tree.
* Clixon XML XPath 1.0 according to https://www.w3.org/TR/xpath-10
* This file defines XPath contexts using in traversing the XPath parse tree.
*/
#ifndef _CLIXON_XPATH_CTX_H
#define _CLIXON_XPATH_CTX_H
@ -43,7 +43,8 @@
* Types
*/
/*! XPATH expression type
/*! XPath expression type
*
* An expression is evaluated to yield an object, which has one of the following four basic types:
* node-set (an unordered collection of nodes without duplicates)
* boolean (true or false)

View file

@ -32,7 +32,7 @@
***** END LICENSE BLOCK *****
* Clixon XML XPATH 1.0 according to https://www.w3.org/TR/xpath-10
* Clixon XML XPath 1.0 according to https://www.w3.org/TR/xpath-10
* See XPATH_LIST_OPTIMIZE
*/
#ifndef _CLIXON_XPATH_OPTIMIZE_H
@ -40,7 +40,7 @@
int xpath_list_optimize_stats(int *hits);
int xpath_list_optimize_set(int enable);
int xpath_list_optimize_set(int enable);
void xpath_optimize_exit(void);
int xpath_optimize_check(xpath_tree *xs, cxobj *xv, cxobj ***xvec0, int *xlen0);

View file

@ -32,9 +32,9 @@
***** END LICENSE BLOCK *****
* Clixon XML XPATH 1.0 according to https://www.w3.org/TR/xpath-10
* Clixon XML XPath 1.0 according to https://www.w3.org/TR/xpath-10
* Note: for YANG which is constrained to path-arg as defined in rfc7950
* See: clixon_xpath.[ch] for full XML XPATH implementation
* See: clixon_xpath.[ch] for full XML XPath implementation
*/
#ifndef _CLIXON_XPATH_YANG_H
#define _CLIXON_XPATH_YANG_H

View file

@ -49,7 +49,7 @@
#define V_UNSET 0x10 /* Used by XML code to denote a value is not default */
/*
* Yang flags used in
* Yang flags used in
*/
#define YANG_FLAG_MARK 0x01 /* (Dynamic) marker for dynamic algorithms, eg expand and DAG */
#define YANG_FLAG_TMP 0x02 /* (Dynamic) marker for dynamic algorithms, eg DAG detection */
@ -66,7 +66,7 @@
#define YANG_FLAG_CONFIG_VALUE 0x20 /* Ancestor config cache value */
#endif
#define YANG_FLAG_DISABLED 0x40 /* Disabled due to if-feature evaluate to false
#define YANG_FLAG_DISABLED 0x40 /* Disabled due to if-feature evaluate to false
* Transformed to ANYDATA but some code may need to check
* why it is an ANYDATA
*/
@ -88,6 +88,7 @@
* Types
*/
/*! YANG keywords from RFC6020.
*
* See also keywords generated by yacc/bison in clicon_yang_parse.tab.h, but they start with K_
* instead of Y_
* Wanted to unify these (K_ and Y_) but gave up for several reasons:
@ -129,7 +130,7 @@ enum rfc_6020{
Y_LEAF,
Y_LEAF_LIST,
Y_LENGTH,
Y_LIST,
Y_LIST,
Y_MANDATORY,
Y_MAX_ELEMENTS,
Y_MIN_ELEMENTS,
@ -183,14 +184,15 @@ struct xml;
/* This is the external handle type exposed in the API.
* The internal struct is defined in clixon_yang_internal.h */
typedef struct yang_stmt yang_stmt;
typedef struct yang_stmt yang_stmt;
/*! Yang apply function worker
*
* @param[in] yn yang node
* @param[in] arg Argument
* @retval -1 Error, abort
* @retval 0 OK, continue with next
* @retval n OK, abort traversal and return to caller with "n"
* @retval 0 OK, continue with next
* @retval -1 Error, abort
*/
typedef int (yang_applyfn_t)(yang_stmt *ys, void *arg);

View file

@ -47,7 +47,8 @@
* Types
*/
/* Struct containing module state differences between two modules or two
/*! Struct containing module state differences between two modules or two
*
* revisions of same module.
* The most significant usecase is one module-state is a loaded datastore and the other
* is the one loaded by the server by its YANG files.

View file

@ -46,6 +46,7 @@
/* Limitations/deviations from RFC 8528 */
/*! Only support YANG presende containers as mount-points
*
* This is a limitation of othe current implementation
*/
#define YANG_SCHEMA_MOUNT_ONLY_PRESENCE_CONTAINERS

View file

@ -62,13 +62,13 @@ yang_stmt *yang_find_identity(yang_stmt *ys, char *identity);
yang_stmt *yang_find_identity_nsc(yang_stmt *yspec, char *identity, cvec *nsc);
int ys_cv_validate(clicon_handle h, cg_var *cv, yang_stmt *ys, yang_stmt **ysub, char **reason);
int clicon_type2cv(char *type, char *rtype, yang_stmt *ys, enum cv_type *cvtype);
int yang_type_get(yang_stmt *ys, char **otype, yang_stmt **restype,
int yang_type_get(yang_stmt *ys, char **otype, yang_stmt **restype,
int *options, cvec **cvv,
cvec *patterns, cvec *regexps,
uint8_t *fraction_digits);
int yang_type_resolve(yang_stmt *yorig, yang_stmt *ys,
yang_stmt *ytype,
yang_stmt **restype, int *options,
yang_stmt *ytype,
yang_stmt **restype, int *options,
cvec **cvv, cvec *patterns, cvec *regexps,
uint8_t *fraction);
enum cv_type yang_type2cv(yang_stmt *ys);

View file

@ -40,7 +40,7 @@
/*
* Types
*/
struct clixon_api_path_yacc {
struct clixon_api_path_yacc {
const char *ay_name; /* Name of syntax (for error string) */
int ay_linenum; /* Number of \n in parsed buffer */
char *ay_parse_string; /* original (copy of) parse string */

View file

@ -86,7 +86,7 @@
#define _YYERROR(msg) {clicon_err(OE_XML, 0, "YYERROR %s '%s' %d", (msg), clixon_api_path_parsetext, _AY->ay_linenum); YYERROR;}
/* add _yy to error parameters */
#define YY_(msgid) msgid
#define YY_(msgid) msgid
#include "clixon_config.h"
@ -116,29 +116,29 @@
/* Best debugging is to enable PARSE_DEBUG below and add -d to the LEX compile statement in the Makefile
* And then run the testcase with -D 1
* Disable it to stop any calls to clicon_debug. Having it on by default would mean very large debug outputs.
* Disable it to stop any calls to clixon_debug. Having it on by default would mean very large debug outputs.
*/
#if 0
#define _PARSE_DEBUG(s) clicon_debug(1,(s))
#define _PARSE_DEBUG1(s, s1) clicon_debug(1,(s), (s1))
#define _PARSE_DEBUG(s) clixon_debug(1,(s))
#define _PARSE_DEBUG1(s, s1) clixon_debug(1,(s), (s1))
#else
#define _PARSE_DEBUG(s)
#define _PARSE_DEBUG1(s, s1)
#endif
/*
/*
* Also called from yacc generated code *
*/
void
void
clixon_api_path_parseerror(void *_ay,
char *s)
{
clicon_err(OE_XML, 0, "%s on line %d: %s at or before: '%s'",
char *s)
{
clicon_err(OE_XML, 0, "%s on line %d: %s at or before: '%s'",
_AY->ay_name,
_AY->ay_linenum ,
s,
clixon_api_path_parsetext);
return;
_AY->ay_linenum,
s,
clixon_api_path_parsetext);
return;
}
int
@ -159,20 +159,20 @@ static clixon_path *
path_append(clixon_path *list,
clixon_path *new)
{
clicon_debug(CLIXON_DBG_DETAIL, "%s()", __FUNCTION__);
clixon_debug(CLIXON_DBG_DETAIL, "%s()", __FUNCTION__);
if (new == NULL)
return NULL;
ADDQ(new, list);
return list;
}
/*! Add keyvalue to existing clixon path
/*! Add keyvalue to existing clixon path
*/
static clixon_path *
path_add_keyvalue(clixon_path *cp,
cvec *cvk)
{
clicon_debug(CLIXON_DBG_DETAIL, "%s()", __FUNCTION__);
clixon_debug(CLIXON_DBG_DETAIL, "%s()", __FUNCTION__);
if (cp)
cp->cp_cvk = cvk;
return cp;
@ -184,7 +184,7 @@ path_new(char *module_name,
{
clixon_path *cp = NULL;
clicon_debug(CLIXON_DBG_DETAIL, "%s(%s,%s)", __FUNCTION__, module_name, id);
clixon_debug(CLIXON_DBG_DETAIL, "%s(%s,%s)", __FUNCTION__, module_name, id);
if ((cp = malloc(sizeof(*cp))) == NULL){
clicon_err(OE_UNIX, errno, "malloc");
goto done;
@ -205,6 +205,7 @@ path_new(char *module_name,
}
/*! Append a key-value cv to a cvec, create the cvec if not exist
*
* @param[in] cvv Either created cvv or NULL, in whihc case it is created
* @param[in] cv Is consumed by thius function (if appended)
* @retval NULL Error
@ -214,7 +215,7 @@ static cvec *
keyval_add(cvec *cvv,
cg_var *cv)
{
clicon_debug(CLIXON_DBG_DETAIL, "%s()", __FUNCTION__);
clixon_debug(CLIXON_DBG_DETAIL, "%s()", __FUNCTION__);
if (cv == NULL)
goto done;
if (cvv == NULL &&
@ -240,7 +241,7 @@ keyval_set(char *name,
{
cg_var *cv = NULL;
clicon_debug(CLIXON_DBG_DETAIL, "%s(%s=%s)", __FUNCTION__, name?name:"NULL", val);
clixon_debug(CLIXON_DBG_DETAIL, "%s(%s=%s)", __FUNCTION__, name?name:"NULL", val);
if ((cv = cv_new(CGV_STRING)) == NULL){
clicon_err(OE_UNIX, errno, "cv_new");
goto done;
@ -259,24 +260,23 @@ keyval_set(char *name,
return cv;
}
%}
%}
%%
/*
*/
start : list X_EOF {_PARSE_DEBUG("top");_AY->ay_top=$1; YYACCEPT; }
start : list X_EOF {_PARSE_DEBUG("top");_AY->ay_top=$1; YYACCEPT; }
;
list : list SLASH element { if (($$ = path_append($1, $3)) == NULL) YYABORT;
list : list SLASH element { if (($$ = path_append($1, $3)) == NULL) YYABORT;
_PARSE_DEBUG("list = list / element");}
| { $$ = NULL;
_PARSE_DEBUG("list = ");}
;
element : api_identifier { $$=$1;
element : api_identifier { $$=$1;
_PARSE_DEBUG("element = api_identifier");}
| list_instance { $$=$1;
_PARSE_DEBUG("element = list_instance");}

View file

@ -117,8 +117,8 @@ clixon_handle
clixon_client_init(const char *config_file)
{
clicon_handle h;
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
/* Initiate CLICON handle. CLIgen is also initialized */
if ((h = clicon_handle_init()) == NULL)
return NULL;
@ -139,7 +139,7 @@ clixon_client_init(const char *config_file)
int
clixon_client_terminate(clicon_handle h)
{
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
clicon_handle_exit(h);
return 0;
}
@ -165,8 +165,8 @@ clixon_client_lock(int sock,
cbuf *msg = NULL;
cbuf *msgret = NULL;
int eof = 0;
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
if (db == NULL){
clicon_err(OE_XML, EINVAL, "Expected db");
goto done;
@ -200,7 +200,7 @@ clixon_client_lock(int sock,
}
retval = 0;
done:
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
clixon_debug(CLIXON_DBG_DEFAULT, "%s retval:%d", __FUNCTION__, retval);
if (xret)
xml_free(xret);
if (msg)
@ -225,8 +225,8 @@ clixon_client_hello(int sock,
{
int retval = -1;
cbuf *msg = NULL;
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
if ((msg = cbuf_new()) == NULL){
clicon_err(OE_PLUGIN, errno, "cbuf_new");
goto done;
@ -242,7 +242,7 @@ clixon_client_hello(int sock,
goto done;
retval = 0;
done:
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
clixon_debug(CLIXON_DBG_DEFAULT, "%s retval:%d", __FUNCTION__, retval);
if (msg)
cbuf_free(msg);
return retval;
@ -263,7 +263,7 @@ clixon_client_connect_netconf(clicon_handle h,
char dbgstr[8];
nr = 7;
if (clicon_debug_get() != 0)
if (clixon_debug_get() != 0)
nr += 2;
if ((argv = calloc(nr, sizeof(char *))) == NULL){
clicon_err(OE_UNIX, errno, "calloc");
@ -273,7 +273,7 @@ clixon_client_connect_netconf(clicon_handle h,
if ((netconf_bin = getenv("CLIXON_NETCONF_BIN")) == NULL)
netconf_bin = CLIXON_NETCONF_BIN;
if (stat(netconf_bin, &st) < 0){
clicon_err(OE_NETCONF, errno, "netconf binary %s. Set with CLIXON_NETCONF_BIN=",
clicon_err(OE_NETCONF, errno, "netconf binary %s. Set with CLIXON_NETCONF_BIN=",
netconf_bin);
goto done;
}
@ -283,9 +283,9 @@ clixon_client_connect_netconf(clicon_handle h,
argv[i++] = clicon_option_str(h, "CLICON_CONFIGFILE");
argv[i++] = "-l"; /* log to syslog */
argv[i++] = "s";
if (clicon_debug_get() != 0){
if (clixon_debug_get() != 0){
argv[i++] = "-D";
snprintf(dbgstr, sizeof(dbgstr)-1, "%d", clicon_debug_get());
snprintf(dbgstr, sizeof(dbgstr)-1, "%d", clixon_debug_get());
argv[i++] = dbgstr;
}
argv[i++] = NULL;
@ -312,7 +312,7 @@ clixon_client_connect_ssh(clicon_handle h,
char *ssh_bin = SSH_BIN;
struct stat st = {0,};
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
nr = 5;
if ((argv = calloc(nr, sizeof(char *))) == NULL){
clicon_err(OE_UNIX, errno, "calloc");
@ -330,7 +330,7 @@ clixon_client_connect_ssh(clicon_handle h,
argv[i++] = NULL;
assert(i==nr);
for (i=0;i<nr;i++)
clicon_debug(1, "%s: argv[%d]:%s", __FUNCTION__, i, argv[i]);
clixon_debug(CLIXON_DBG_DEFAULT, "%s: argv[%d]:%s", __FUNCTION__, i, argv[i]);
if (clixon_proc_socket(argv, SOCK_STREAM, &cch->cch_pid, &cch->cch_socket) < 0){
goto done;
}
@ -355,8 +355,8 @@ clixon_client_connect(clicon_handle h,
{
struct clixon_client_handle *cch = NULL;
size_t sz = sizeof(struct clixon_client_handle);
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
if ((cch = malloc(sz)) == NULL){
clicon_err(OE_NETCONF, errno, "malloc");
goto done;
@ -384,7 +384,7 @@ clixon_client_connect(clicon_handle h,
break;
} /* switch */
done:
clicon_debug(1, "%s retval:%p", __FUNCTION__, cch);
clixon_debug(CLIXON_DBG_DEFAULT, "%s retval:%p", __FUNCTION__, cch);
return cch;
err:
if (cch)
@ -406,8 +406,8 @@ clixon_client_disconnect(clixon_client_handle ch)
{
int retval = -1;
struct clixon_client_handle *cch = chandle(ch);
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
if (cch == NULL){
clicon_err(OE_XML, EINVAL, "Expected cch handle");
goto done;
@ -447,7 +447,7 @@ clixon_xml_bottom(cxobj *xtop,
cxobj *x;
cxobj *xp;
cxobj *xc = NULL;
xp = xtop;
while (xp != NULL){
/* Find child, if many, one which is not a key, if any */
@ -491,10 +491,10 @@ clixon_client_get_xdata(int sock,
cbuf *msg = NULL;
cbuf *msgret = NULL;
const char *db = "running";
cvec *nsc = NULL;
cvec *nsc = NULL;
int eof = 0;
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
if ((msg = cbuf_new()) == NULL){
clicon_err(OE_PLUGIN, errno, "cbuf_new");
goto done;
@ -549,7 +549,7 @@ clixon_client_get_xdata(int sock,
*xdata = xd;
retval = 0;
done:
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
clixon_debug(CLIXON_DBG_DEFAULT, "%s retval:%d", __FUNCTION__, retval);
if (xret)
xml_free(xret);
if (msg)
@ -579,8 +579,8 @@ clixon_client_get_body_val(int sock,
int retval = -1;
cxobj *xdata = NULL;
cxobj *xobj = NULL;
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
if (val == NULL){
clicon_err(OE_XML, EINVAL, "Expected val");
goto done;
@ -588,24 +588,24 @@ clixon_client_get_body_val(int sock,
if (clixon_client_get_xdata(sock, descr, namespace, xpath, &xdata) < 0)
goto done;
if (xdata == NULL){
clicon_err(OE_XML, EINVAL, "No xml obj found");
clicon_err(OE_XML, EINVAL, "No xml obj found");
goto done;
}
/* Is this an error, maybe an "unset" retval ? */
if (xml_child_nr_type(xdata, CX_ELMNT) == 0){
clicon_err(OE_XML, EINVAL, "Value not found");
clicon_err(OE_XML, EINVAL, "Value not found");
goto done;
}
if (clixon_xml_bottom(xdata, &xobj) < 0)
goto done;
if (xobj == NULL){
clicon_err(OE_XML, EINVAL, "No xml value found");
clicon_err(OE_XML, EINVAL, "No xml value found");
goto done;
}
*val = xml_body(xobj);
retval = 0;
done:
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
clixon_debug(CLIXON_DBG_DEFAULT, "%s retval:%d", __FUNCTION__, retval);
return retval;
}
@ -630,17 +630,17 @@ clixon_client_get_bool(clixon_client_handle ch,
char *reason = NULL;
int ret;
uint8_t val0=0;
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
if (clixon_client_get_body_val(cch->cch_socket, cch->cch_descr,
namespace, xpath, &val) < 0)
goto done;
if ((ret = parse_bool(val, &val0, &reason)) < 0){
clicon_err(OE_XML, errno, "parse_bool");
clicon_err(OE_XML, errno, "parse_bool");
goto done;
}
if (ret == 0){
clicon_err(OE_XML, EINVAL, "%s", reason);
clicon_err(OE_XML, EINVAL, "%s", reason);
goto done;
}
*rval = (int)val0;
@ -671,8 +671,8 @@ clixon_client_get_str(clixon_client_handle ch,
int retval = -1;
struct clixon_client_handle *cch = chandle(ch);
char *val = NULL;
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
if (clixon_client_get_body_val(cch->cch_socket, cch->cch_descr,
namespace, xpath, &val) < 0)
goto done;
@ -703,17 +703,17 @@ clixon_client_get_uint8(clixon_client_handle ch,
char *val = NULL;
char *reason = NULL;
int ret;
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
if (clixon_client_get_body_val(cch->cch_socket, cch->cch_descr,
namespace, xpath, &val) < 0)
goto done;
if ((ret = parse_uint8(val, rval, &reason)) < 0){
clicon_err(OE_XML, errno, "parse_bool");
clicon_err(OE_XML, errno, "parse_bool");
goto done;
}
if (ret == 0){
clicon_err(OE_XML, EINVAL, "%s", reason);
clicon_err(OE_XML, EINVAL, "%s", reason);
goto done;
}
retval = 0;
@ -743,17 +743,17 @@ clixon_client_get_uint16(clixon_client_handle ch,
char *val = NULL;
char *reason = NULL;
int ret;
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
if (clixon_client_get_body_val(cch->cch_socket, cch->cch_descr,
namespace, xpath, &val) < 0)
goto done;
if ((ret = parse_uint16(val, rval, &reason)) < 0){
clicon_err(OE_XML, errno, "parse_bool");
clicon_err(OE_XML, errno, "parse_bool");
goto done;
}
if (ret == 0){
clicon_err(OE_XML, EINVAL, "%s", reason);
clicon_err(OE_XML, EINVAL, "%s", reason);
goto done;
}
retval = 0;
@ -784,25 +784,25 @@ clixon_client_get_uint32(clixon_client_handle ch,
char *reason = NULL;
int ret;
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
if (clixon_client_get_body_val(cch->cch_socket, cch->cch_descr,
namespace, xpath, &val) < 0)
goto done;
if (val == NULL){
clicon_err(OE_XML, EFAULT, "val is NULL");
clicon_err(OE_XML, EFAULT, "val is NULL");
goto done;
}
if ((ret = parse_uint32(val, rval, &reason)) < 0){
clicon_err(OE_XML, errno, "parse_bool");
clicon_err(OE_XML, errno, "parse_bool");
goto done;
}
if (ret == 0){
clicon_err(OE_XML, EINVAL, "%s", reason);
clicon_err(OE_XML, EINVAL, "%s", reason);
goto done;
}
retval = 0;
done:
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
clixon_debug(CLIXON_DBG_DEFAULT, "%s retval:%d", __FUNCTION__, retval);
if (reason)
free(reason);
return retval;
@ -828,17 +828,17 @@ clixon_client_get_uint64(clixon_client_handle ch,
char *val = NULL;
char *reason = NULL;
int ret;
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
if (clixon_client_get_body_val(cch->cch_socket, cch->cch_descr,
namespace, xpath, &val) < 0)
goto done;
if ((ret = parse_uint64(val, rval, &reason)) < 0){
clicon_err(OE_XML, errno, "parse_bool");
clicon_err(OE_XML, errno, "parse_bool");
goto done;
}
if (ret == 0){
clicon_err(OE_XML, EINVAL, "%s", reason);
clicon_err(OE_XML, EINVAL, "%s", reason);
goto done;
}
retval = 0;

View file

@ -78,7 +78,8 @@
#include "clixon_data.h"
/*! Get generic clixon data on the form <name>=<val> where <val> is string
* @param[in] h Clicon handle
*
* @param[in] h Clixon handle
* @param[in] name Data name
* @param[out] val Data value as string
* @retval 0 OK
@ -100,7 +101,8 @@ clicon_data_get(clicon_handle h,
}
/*! Set generic clixon data on the form <name>=<val> where <val> is string
* @param[in] h Clicon handle
*
* @param[in] h Clixon handle
* @param[in] name Data name
* @param[in] val Data value as null-terminated string (copied)
* @retval 0 OK
@ -108,7 +110,7 @@ clicon_data_get(clicon_handle h,
* @see clicon_option_str_set
*/
int
clicon_data_set(clicon_handle h,
clicon_data_set(clicon_handle h,
const char *name,
char *val)
{
@ -118,14 +120,15 @@ clicon_data_set(clicon_handle h,
}
/*! Delete generic clixon data
* @param[in] h Clicon handle
*
* @param[in] h Clixon handle
* @param[in] name Data name
* @retval 0 OK
* @retval -1 Error
* @see clicon_option_del
*/
int
clicon_data_del(clicon_handle h,
clicon_data_del(clicon_handle h,
const char *name)
{
clicon_hash_t *cdat = clicon_data(h);
@ -134,7 +137,8 @@ clicon_data_del(clicon_handle h,
}
/*! Get generic clixon data on the form <name>=<ptr> where <ptr> is void*
* @param[in] h Clicon handle
*
* @param[in] h Clixon handle
* @param[in] name Data name
* @param[out] ptr Pointer
* @retval 0 OK
@ -160,7 +164,8 @@ clicon_ptr_get(clicon_handle h,
}
/*! Set generic clixon data on the form <name>=<ptr> where <ptr> is void*
* @param[in] h Clicon handle
*
* @param[in] h Clixon handle
* @param[in] name Data name
* @param[in] ptr Pointer
* @retval 0 OK
@ -168,7 +173,7 @@ clicon_ptr_get(clicon_handle h,
* @see clicon_option_str_set
*/
int
clicon_ptr_set(clicon_handle h,
clicon_ptr_set(clicon_handle h,
const char *name,
void *ptr)
{
@ -178,14 +183,15 @@ clicon_ptr_set(clicon_handle h,
}
/*! Delete generic clixon data
* @param[in] h Clicon handle
*
* @param[in] h Clixon handle
* @param[in] name Data name
* @retval 0 OK
* @retval -1 Error
* @see clicon_option_del
*/
int
clicon_ptr_del(clicon_handle h,
clicon_ptr_del(clicon_handle h,
const char *name)
{
clicon_hash_t *cdat = clicon_data(h);
@ -195,7 +201,7 @@ clicon_ptr_del(clicon_handle h,
/*! Get generic cligen variable vector (cvv) on the form <name>=<val> where <val> is cvv
*
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] name Data name
* @retval cvv Data value as cvv
* @retval NULL Not found (or error)
@ -210,14 +216,15 @@ clicon_data_cvec_get(clicon_handle h,
const char *name)
{
cvec *cvv = NULL;
if (clicon_ptr_get(h, name, (void**)&cvv) < 0)
return NULL;
return cvv;
}
/*! Set generic cligen variable vector (cvv) on the form <name>=<val> where <val> is cvv
* @param[in] h Clicon handle
*
* @param[in] h Clixon handle
* @param[in] name Name
* @param[in] cvv CLIgen variable vector (cvv) (malloced)
*/
@ -235,7 +242,8 @@ clicon_data_cvec_set(clicon_handle h,
}
/*! Delete generic cligen variable vector (cvv)
* @param[in] h Clicon handle
*
* @param[in] h Clixon handle
* @param[in] name Name
*/
int
@ -272,7 +280,7 @@ clicon_data_int_get(clicon_handle h,
return atoi(s);
}
/*! Set a single string data via handle
/*! Set a single string data via handle
*
* @param[in] h clicon_handle
* @param[in] name option name
@ -310,7 +318,8 @@ clicon_data_int_del(clicon_handle h,
}
/*! Get data yangspec, yspec
* @param[in] h Clicon handle
*
* @param[in] h Clixon handle
* @retval yspec Yang spec
* @see clicon_config_yang for the configuration yang
*/
@ -318,26 +327,28 @@ yang_stmt *
clicon_dbspec_yang(clicon_handle h)
{
yang_stmt *ys = NULL;
if (clicon_ptr_get(h, "dbspec_yang", (void**)&ys) < 0)
return NULL;
return ys;
}
/*! Set yang specification for application specifications
* @param[in] h Clicon handle
*
* @param[in] h Clixon handle
* @param[in] yspec Yang spec (malloced pointer)
* @see clicon_config_yang_set for the configuration yang
*/
int
clicon_dbspec_yang_set(clicon_handle h,
clicon_dbspec_yang_set(clicon_handle h,
yang_stmt *ys)
{
return clicon_ptr_set(h, "dbspec_yang", ys);
}
/*! Get YANG specification for clixon config (separate from application yangs)
* @param[in] h Clicon handle
*
* @param[in] h Clixon handle
* @retval yspec Yang spec
* @see clicon_dbspec_yang for the application specs
*/
@ -345,26 +356,28 @@ yang_stmt *
clicon_config_yang(clicon_handle h)
{
yang_stmt *ys = NULL;
if (clicon_ptr_get(h, "control_yang", (void**)&ys) < 0)
return NULL;
return ys;
}
/*! Set yang specification for configuration
* @param[in] h Clicon handle
*
* @param[in] h Clixon handle
* @param[in] yspec Yang spec (malloced pointer)
* @see clicon_dbspec_yang_set for the application specs
*/
int
clicon_config_yang_set(clicon_handle h,
clicon_config_yang_set(clicon_handle h,
yang_stmt *ys)
{
return clicon_ptr_set(h, "control_yang", ys);
}
/*! Get YANG specification for external NACM (separate from application yangs)
* @param[in] h Clicon handle
*
* @param[in] h Clixon handle
* @retval yspec Yang spec
* @see clicon_nacm_ext for external NACM XML
*/
@ -372,27 +385,29 @@ yang_stmt *
clicon_nacm_ext_yang(clicon_handle h)
{
yang_stmt *ys = NULL;
if (clicon_ptr_get(h, "nacm_ext_yang", (void**)&ys) < 0)
return NULL;
return ys;
}
/*! Set yang specification for external NACM
* @param[in] h Clicon handle
*
* @param[in] h Clixon handle
* @param[in] yspec Yang spec (malloced pointer)
* @see clicon_nacm_ext_set for external NACM XML
*/
int
clicon_nacm_ext_yang_set(clicon_handle h,
clicon_nacm_ext_yang_set(clicon_handle h,
yang_stmt *ys)
{
return clicon_ptr_set(h, "nacm_ext_yang", ys);
}
/*! Get Global "canonical" namespace context
*
* Canonical: use prefix and namespace specified in the yang modules.
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @retval nsctx Namespace context (malloced)
* @code
* cvec *nsctx;
@ -403,15 +418,16 @@ cvec *
clicon_nsctx_global_get(clicon_handle h)
{
cvec *cvv = NULL;
if (clicon_ptr_get(h, "nsctx_global", (void**)&cvv) < 0)
return NULL;
return cvv;
}
/*! Set global "canonical" namespace context
*
* Canonical: use prefix and namespace specified in the yang modules.
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] nsctx Namespace context (malloced)
*/
int
@ -422,7 +438,8 @@ clicon_nsctx_global_set(clicon_handle h,
}
/*! Get NACM (rfc 8341) XML parse tree if external not in std xml config
* @param[in] h Clicon handle
*
* @param[in] h Clixon handle
* @retval xn XML NACM tree, or NULL
* @note only used if config option CLICON_NACM_MODE is external
* @see clicon_nacm_ext_set
@ -431,14 +448,15 @@ cxobj *
clicon_nacm_ext(clicon_handle h)
{
cxobj *x = NULL;
if (clicon_ptr_get(h, "nacm_xml", (void**)&x) < 0)
return NULL;
return x;
}
/*! Set NACM (rfc 8341) external XML parse tree, free old if any
* @param[in] h Clicon handle
*
* @param[in] h Clixon handle
* @param[in] xn XML Nacm tree
* @note only used if config option CLICON_NACM_MODE is external
* @see clicon_nacm_ext
@ -455,7 +473,8 @@ clicon_nacm_ext_set(clicon_handle h,
}
/*! Get NACM (rfc 8341) XML parse tree cache
* @param[in] h Clicon handle
*
* @param[in] h Clixon handle
* @retval xn XML NACM tree, or NULL. Direct pointer, no copying
* @note Use with caution, only valid on a stack, direct pointer freed on function return
* @see from_client_msg
@ -464,14 +483,15 @@ cxobj *
clicon_nacm_cache(clicon_handle h)
{
cxobj *x = NULL;
if (clicon_ptr_get(h, "nacm_cache", (void**)&x) < 0)
return NULL;
return x;
}
/*! Set NACM (rfc 8341) external XML parse tree cache
* @param[in] h Clicon handle
*
* @param[in] h Clixon handle
* @param[in] xn XML Nacm tree direct pointer, no copying
* @note Use with caution, only valid on a stack, direct pointer freed on function return
* @see from_client_msg
@ -484,6 +504,7 @@ clicon_nacm_cache_set(clicon_handle h,
}
/*! Get YANG specification for Clixon system options and features
*
* Must use hash functions directly since they are not strings.
* Example: features are typically accessed directly in the config tree.
* @code
@ -498,17 +519,18 @@ cxobj *
clicon_conf_xml(clicon_handle h)
{
cxobj *x = NULL;
if (clicon_ptr_get(h, "clixon_conf", (void**)&x) < 0)
return NULL;
return x;
}
/*! Set YANG specification for Clixon system options and features
*
* ys must be a malloced pointer
*/
int
clicon_conf_xml_set(clicon_handle h,
clicon_conf_xml_set(clicon_handle h,
cxobj *x)
{
return clicon_ptr_set(h, "clixon_conf", x);
@ -517,7 +539,7 @@ clicon_conf_xml_set(clicon_handle h,
/*! Get local YANG specification for Clixon-restconf.yang tree
*
* That is, get the XML of clixon-config/restconf container of clixon-config.yang
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @retval x XML tree containing restconf xml node from clixon-restconf.yang
* @code
* cxobj *xrestconf = clicon_conf_restconf(h);
@ -538,7 +560,7 @@ clicon_conf_restconf(clicon_handle h)
/*! Get clixon-autocli.yang part of the clixon config tree
*
* That is, get the XML of clixon-config/autocli container of clixon-config.yang
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @retval x XML tree containing clispec xml node from clixon-autoclu.yang
* @code
* cxobj *xautocli = clicon_conf_autocli(h);
@ -555,7 +577,8 @@ clicon_conf_autocli(clicon_handle h)
}
/*! Get authorized user name
* @param[in] h Clicon handle
*
* @param[in] h Clixon handle
* @retval username
*/
char *
@ -567,12 +590,13 @@ clicon_username_get(clicon_handle h)
}
/*! Set authorized user name
* @param[in] h Clicon handle
*
* @param[in] h Clixon handle
* @param[in] username
* @note Just keep note of it, dont allocate it or so.
*/
int
clicon_username_set(clicon_handle h,
clicon_username_set(clicon_handle h,
void *username)
{
clicon_hash_t *cdat = clicon_data(h);
@ -583,7 +607,8 @@ clicon_username_set(clicon_handle h,
}
/*! Get backend daemon startup status
* @param[in] h Clicon handle
*
* @param[in] h Clixon handle
* @retval status Startup status
*/
enum startup_status
@ -598,7 +623,8 @@ clicon_startup_status_get(clicon_handle h)
}
/*! Set backend daemon startup status
* @param[in] h Clicon handle
*
* @param[in] h Clixon handle
* @param[in] status Startup status
* @retval 0 OK
* @retval -1 Error (when setting value)
@ -614,9 +640,10 @@ clicon_startup_status_set(clicon_handle h,
}
/*! Get server socket fd (ie backend server socket / restconf fcgi socket)
* @param[in] h Clicon handle
* @retval -1 No open socket
*
* @param[in] h Clixon handle
* @retval s Socket
* @retval -1 No open socket
*/
int
clicon_socket_get(clicon_handle h)
@ -630,13 +657,14 @@ clicon_socket_get(clicon_handle h)
}
/*! Set server socket fd (ie backend server socket / restconf fcgi socket)
* @param[in] h Clicon handle
* @param[in] s Open socket (or -1 to close)
* @retval 0 OK
* @retval -1 Error
*
* @param[in] h Clixon handle
* @param[in] s Open socket (or -1 to close)
* @retval 0 OK
* @retval -1 Error
*/
int
clicon_socket_set(clicon_handle h,
clicon_socket_set(clicon_handle h,
int s)
{
clicon_hash_t *cdat = clicon_data(h);
@ -647,9 +675,10 @@ clicon_socket_set(clicon_handle h,
}
/*! Get client socket fd (ie client cli / netconf / restconf / client-api socket
* @param[in] h Clicon handle
* @retval -1 No open socket
*
* @param[in] h Clixon handle
* @retval s Socket
* @retval -1 No open socket
*/
int
clicon_client_socket_get(clicon_handle h)
@ -663,13 +692,14 @@ clicon_client_socket_get(clicon_handle h)
}
/*! Set client socket fd (ie client cli / netconf / restconf / client-api socket
* @param[in] h Clicon handle
*
* @param[in] h Clixon handle
* @param[in] s Open socket (or -1 to close)
* @retval 0 OK
* @retval -1 Error
* @retval 0 OK
* @retval -1 Error
*/
int
clicon_client_socket_set(clicon_handle h,
clicon_client_socket_set(clicon_handle h,
int s)
{
clicon_hash_t *cdat = clicon_data(h);
@ -680,7 +710,8 @@ clicon_client_socket_set(clicon_handle h,
}
/*! Get module state cache
* @param[in] h Clicon handle
*
* @param[in] h Clixon handle
* @param[in] brief 0: Full module state tree, 1: Brief tree (datastore)
* @retval xms Module state cache XML tree
* xms is on the form: <modules-state>...
@ -698,11 +729,12 @@ clicon_modst_cache_get(clicon_handle h,
}
/*! Set module state cache
* @param[in] h Clicon handle
* @param[in] brief 0: Full module state tree, 1: Brief tree (datastore)
* @param[in] xms Module state cache XML tree
* @retval 0 OK
* @retval -1 Error
*
* @param[in] h Clixon handle
* @param[in] brief 0: Full module state tree, 1: Brief tree (datastore)
* @param[in] xms Module state cache XML tree
* @retval 0 OK
* @retval -1 Error
*/
int
clicon_modst_cache_set(clicon_handle h,
@ -725,7 +757,8 @@ clicon_modst_cache_set(clicon_handle h,
}
/*! Get yang module changelog
* @param[in] h Clicon handle
*
* @param[in] h Clixon handle
* @retval xch Module revision changelog XML tree
* @see draft-wang-netmod-module-revision-management-01
*/
@ -741,14 +774,15 @@ clicon_xml_changelog_get(clicon_handle h)
}
/*! Set xml module changelog
* @param[in] h Clicon handle
*
* @param[in] h Clixon handle
* @param[in] s Module revision changelog XML tree
* @retval 0 OK
* @retval -1 Error
* @see draft-wang-netmod-module-revision-management-01
*/
int
clicon_xml_changelog_set(clicon_handle h,
clicon_xml_changelog_set(clicon_handle h,
cxobj *xchlog)
{
clicon_hash_t *cdat = clicon_data(h);
@ -759,7 +793,8 @@ clicon_xml_changelog_set(clicon_handle h,
}
/*! Get user clicon command-line options argv, argc (after --)
* @param[in] h Clicon handle
*
* @param[in] h Clixon handle
* @param[out] argc
* @param[out] argv
* @retval 0 OK
@ -769,7 +804,6 @@ int
clicon_argv_get(clicon_handle h,
int *argc,
char ***argv)
{
clicon_hash_t *cdat = clicon_data(h);
void *p;
@ -788,7 +822,8 @@ clicon_argv_get(clicon_handle h,
}
/*! Set clicon user command-line options argv, argc (after --)
* @param[in] h Clicon handle
*
* @param[in] h Clixon handle
* @param[in] prog argv[0] - the program name
* @param[in] argc Length of argv
* @param[in] argv Array of command-line options or NULL
@ -797,7 +832,7 @@ clicon_argv_get(clicon_handle h,
* @note If argv=NULL deallocate allocated argv vector if exists.
*/
int
clicon_argv_set(clicon_handle h,
clicon_argv_set(clicon_handle h,
char *prgm,
int argc,
char **argv)
@ -806,7 +841,7 @@ clicon_argv_set(clicon_handle h,
clicon_hash_t *cdat = clicon_data(h);
char **argvv = NULL;
size_t len;
/* add space for null-termination and argv[0] program name */
len = argc+2;
if ((argvv = calloc(len, sizeof(char*))) == NULL){
@ -816,7 +851,7 @@ clicon_argv_set(clicon_handle h,
memcpy(argvv+1, argv, argc*sizeof(char*));
argvv[0] = prgm;
/* Note the value is the argv vector (which is copied) */
if (clicon_hash_add(cdat, "argv", argvv, len*sizeof(char*))==NULL)
if (clicon_hash_add(cdat, "argv", argvv, len*sizeof(char*))==NULL)
goto done;
argc += 1;
if (clicon_hash_add(cdat, "argc", &argc, sizeof(argc))==NULL)
@ -829,7 +864,8 @@ clicon_argv_set(clicon_handle h,
}
/*! Get xml database element including id, xml cache, empty on startup and dirty bit
* @param[in] h Clicon handle
*
* @param[in] h Clixon handle
* @param[in] db Name of database
* @retval de Database element
* @retval NULL None found
@ -847,7 +883,8 @@ clicon_db_elmnt_get(clicon_handle h,
}
/*! Set xml database element including id, xml cache, empty on startup and dirty bit
* @param[in] h Clicon handle
*
* @param[in] h Clixon handle
* @param[in] db Name of database
* @param[in] de Database element
* @retval 0 OK
@ -855,7 +892,7 @@ clicon_db_elmnt_get(clicon_handle h,
* @see xmldb_disconnect
*/
int
clicon_db_elmnt_set(clicon_handle h,
clicon_db_elmnt_set(clicon_handle h,
const char *db,
db_elmnt *de)
{
@ -868,7 +905,7 @@ clicon_db_elmnt_set(clicon_handle h,
/*! Get session id
*
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[out] sid Session identifier
* @retval 0 OK
* @retval -1 Session id not set
@ -902,14 +939,15 @@ clicon_session_id_del(clicon_handle h)
}
/*! Set session id
* @param[in] h Clicon handle
*
* @param[in] h Clixon handle
* @param[in] id Session id (in range 1..max uint32)
* @retval 0 OK
* @retval -1 Error
* Session-ids survive TCP sessions that are created for each message sent to the backend.
*/
int
clicon_session_id_set(clicon_handle h,
clicon_session_id_set(clicon_handle h,
uint32_t id)
{
clicon_hash_t *cdat = clicon_data(h);
@ -919,7 +957,8 @@ clicon_session_id_set(clicon_handle h,
}
/*! Get quit-after-upgrade flag
* @param[in] h Clicon handle
*
* @param[in] h Clixon handle
* @retval 1 Flag set: quit startup directly after upgrade
* @retval 0 Flag not set
* If set, quit startup directly after upgrade
@ -936,14 +975,15 @@ clicon_quit_upgrade_get(clicon_handle h)
}
/*! Set quit-after-upgrade flag
* @param[in] h Clicon handle
*
* @param[in] h Clixon handle
* @param[in] val Set or reset flag
* @retval 0 OK
* @retval -1 Error
* If set, quit startup directly after upgrade
*/
int
clicon_quit_upgrade_set(clicon_handle h,
clicon_quit_upgrade_set(clicon_handle h,
int val)
{
clicon_hash_t *cdat = clicon_data(h);

View file

@ -124,7 +124,7 @@ xmldb_db2file(clicon_handle h,
/*! Connect to a datastore plugin, allocate resources to be used in API calls
*
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @retval 0 OK
* @retval -1 Error
*/
@ -167,7 +167,7 @@ xmldb_disconnect(clicon_handle h)
/*! Copy database from db1 to db2
*
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] from Source database
* @param[in] to Destination database
* @retval 0 OK
@ -187,7 +187,7 @@ xmldb_copy(clicon_handle h,
cxobj *x1 = NULL; /* from */
cxobj *x2 = NULL; /* to */
clicon_debug(1, "%s %s %s", __FUNCTION__, from, to);
clixon_debug(CLIXON_DBG_DEFAULT, "%s %s %s", __FUNCTION__, from, to);
/* XXX lock */
if (clicon_datastore_cache(h) != DATASTORE_NOCACHE){
/* Copy in-memory cache */
@ -245,7 +245,7 @@ xmldb_copy(clicon_handle h,
/*! Lock database
*
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] db Database
* @param[in] id Session id
* @retval 0 OK
@ -264,20 +264,20 @@ xmldb_lock(clicon_handle h,
de0.de_id = id;
gettimeofday(&de0.de_tv, NULL);
clicon_db_elmnt_set(h, db, &de0);
clicon_debug(1, "%s: locked by %u", db, id);
clixon_debug(CLIXON_DBG_DEFAULT, "%s: locked by %u", db, id);
return 0;
}
/*! Unlock database
*
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] db Database
* @retval 0 OK
* @retval -1 Error
* Assume all sanity checks have been made
*/
int
xmldb_unlock(clicon_handle h,
int
xmldb_unlock(clicon_handle h,
const char *db)
{
db_elmnt *de = NULL;
@ -292,13 +292,13 @@ xmldb_unlock(clicon_handle h,
/*! Unlock all databases locked by session-id (eg process dies)
*
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] id Session id
* @retval 0 OK
* @retval -1 Error
*/
int
xmldb_unlock_all(clicon_handle h,
xmldb_unlock_all(clicon_handle h,
uint32_t id)
{
int retval = -1;
@ -328,14 +328,14 @@ xmldb_unlock_all(clicon_handle h,
/*! Check if database is locked
*
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] db Database
* @retval >0 Session id of locker
* @retval 0 Not locked
* @retval -1 Error
* @retval -1 Error
*/
uint32_t
xmldb_islocked(clicon_handle h,
xmldb_islocked(clicon_handle h,
const char *db)
{
db_elmnt *de;
@ -347,14 +347,14 @@ xmldb_islocked(clicon_handle h,
/*! Get timestamp of when database was locked
*
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] db Database
* @param[out] tv Timestamp
* @retval 0 OK
* @retval -1 No timestamp / not locked
*/
int
xmldb_lock_timestamp(clicon_handle h,
xmldb_lock_timestamp(clicon_handle h,
const char *db,
struct timeval *tv)
{
@ -368,22 +368,22 @@ xmldb_lock_timestamp(clicon_handle h,
/*! Check if db exists or is empty
*
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] db Database
* @retval 1 Yes it exists
* @retval 0 No it does not exist
* @retval -1 Error
* @note An empty datastore is treated as not existent so that a backend after dropping priviliges can re-create it
*/
int
xmldb_exists(clicon_handle h,
int
xmldb_exists(clicon_handle h,
const char *db)
{
int retval = -1;
char *filename = NULL;
struct stat sb;
clicon_debug(CLIXON_DBG_DETAIL, "%s %s", __FUNCTION__, db);
clixon_debug(CLIXON_DBG_DETAIL, "%s %s", __FUNCTION__, db);
if (xmldb_db2file(h, db, &filename) < 0)
goto done;
if (lstat(filename, &sb) < 0)
@ -403,18 +403,18 @@ xmldb_exists(clicon_handle h,
/*! Clear database cache if any for mem/size optimization only, not file itself
*
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] db Database
* @retval 0 OK
* @retval -1 Error
*/
int
xmldb_clear(clicon_handle h,
int
xmldb_clear(clicon_handle h,
const char *db)
{
cxobj *xt = NULL;
db_elmnt *de = NULL;
if ((de = clicon_db_elmnt_get(h, db)) != NULL){
if ((xt = de->de_xml) != NULL){
xml_free(xt);
@ -426,22 +426,22 @@ xmldb_clear(clicon_handle h,
/*! Delete database, clear cache if any. Remove file
*
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] db Database
* @retval 0 OK
* @retval -1 Error
* @note Datastore is not actually deleted so that a backend after dropping priviliges can re-create it
*/
int
xmldb_delete(clicon_handle h,
int
xmldb_delete(clicon_handle h,
const char *db)
{
int retval = -1;
char *filename = NULL;
struct stat sb;
clicon_debug(CLIXON_DBG_DETAIL, "%s %s", __FUNCTION__, db);
clixon_debug(CLIXON_DBG_DETAIL, "%s %s", __FUNCTION__, db);
if (xmldb_clear(h, db) < 0)
goto done;
if (xmldb_db2file(h, db, &filename) < 0)
@ -460,13 +460,13 @@ xmldb_delete(clicon_handle h,
/*! Create a database. Open database for writing.
*
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] db Database
* @retval 0 OK
* @retval -1 Error
*/
int
xmldb_create(clicon_handle h,
int
xmldb_create(clicon_handle h,
const char *db)
{
int retval = -1;
@ -475,7 +475,7 @@ xmldb_create(clicon_handle h,
db_elmnt *de = NULL;
cxobj *xt = NULL;
clicon_debug(CLIXON_DBG_DETAIL, "%s %s", __FUNCTION__, db);
clixon_debug(CLIXON_DBG_DETAIL, "%s %s", __FUNCTION__, db);
if ((de = clicon_db_elmnt_get(h, db)) != NULL){
if ((xt = de->de_xml) != NULL){
xml_free(xt);
@ -506,11 +506,11 @@ xmldb_create(clicon_handle h,
* @retval -1 Error
*/
int
xmldb_db_reset(clicon_handle h,
xmldb_db_reset(clicon_handle h,
const char *db)
{
if (xmldb_exists(h, db) == 1){
if (xmldb_delete(h, db) != 0 && errno != ENOENT)
if (xmldb_delete(h, db) != 0 && errno != ENOENT)
return -1;
}
if (xmldb_create(h, db) < 0)
@ -520,7 +520,7 @@ xmldb_db_reset(clicon_handle h,
/*! Get datastore XML cache
*
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] db Database name
* @retval xml XML cached tree or NULL
*/
@ -529,7 +529,7 @@ xmldb_cache_get(clicon_handle h,
const char *db)
{
db_elmnt *de;
if ((de = clicon_db_elmnt_get(h, db)) == NULL)
return NULL;
return de->de_xml;
@ -537,7 +537,7 @@ xmldb_cache_get(clicon_handle h,
/*! Get modified flag from datastore
*
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] db Database name
* @retval 1 Db is modified
* @retval 0 Db is not modified
@ -550,7 +550,7 @@ xmldb_modified_get(clicon_handle h,
const char *db)
{
db_elmnt *de;
if ((de = clicon_db_elmnt_get(h, db)) == NULL){
clicon_err(OE_CFG, EFAULT, "datastore %s does not exist", db);
return -1;
@ -560,7 +560,7 @@ xmldb_modified_get(clicon_handle h,
/*! Get empty flag from datastore (the datastore was empty ON LOAD)
*
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] db Database name
* @retval 1 Db was empty on load
* @retval 0 Db was not empty on load
@ -571,7 +571,7 @@ xmldb_empty_get(clicon_handle h,
const char *db)
{
db_elmnt *de;
if ((de = clicon_db_elmnt_get(h, db)) == NULL){
clicon_err(OE_CFG, EFAULT, "datastore %s does not exist", db);
return -1;
@ -581,7 +581,7 @@ xmldb_empty_get(clicon_handle h,
/*! Set modified flag from datastore
*
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] db Database name
* @param[in] value 0 or 1
* @retval 0 OK
@ -595,7 +595,7 @@ xmldb_modified_set(clicon_handle h,
int value)
{
db_elmnt *de;
if ((de = clicon_db_elmnt_get(h, db)) == NULL){
clicon_err(OE_CFG, EFAULT, "datastore %s does not exist", db);
return -1;
@ -611,7 +611,7 @@ xmldb_print(clicon_handle h,
FILE *f)
{
int retval = -1;
db_elmnt *de = NULL;
db_elmnt *de = NULL;
char **keys = NULL;
size_t klen;
int i;
@ -635,7 +635,7 @@ xmldb_print(clicon_handle h,
/*! Rename an XML database
*
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] db Database name
* @param[in] newdb New Database name; if NULL, then same as old
* @param[in] suffix Suffix to append to new database name

View file

@ -49,7 +49,7 @@
#include <unistd.h>
#include <dirent.h>
#include <assert.h>
#include <syslog.h>
#include <syslog.h>
#include <fcntl.h>
/* cligen */
@ -93,7 +93,7 @@
* other error, check specific clicon_errno, clicon_suberrno
*/
static int
singleconfigroot(cxobj *xt,
singleconfigroot(cxobj *xt,
cxobj **xp)
{
int retval = -1;
@ -105,7 +105,7 @@ singleconfigroot(cxobj *xt,
while ((x = xml_child_each(xt, x, CX_ELMNT)) != NULL){
i++;
if (strcmp(xml_name(x), DATASTORE_TOP_SYMBOL)){
clicon_err(OE_DB, ENOENT, "Wrong top-element %s expected %s",
clicon_err(OE_DB, ENOENT, "Wrong top-element %s expected %s",
xml_name(x), DATASTORE_TOP_SYMBOL);
goto done;
}
@ -134,7 +134,7 @@ singleconfigroot(cxobj *xt,
* @retval -1 General error, check specific clicon_errno, clicon_suberrno
*/
static int
xml_copy_bottom_recurse(cxobj *x0t,
xml_copy_bottom_recurse(cxobj *x0t,
cxobj *x0,
cxobj *x1t,
cxobj **x1pp)
@ -189,11 +189,11 @@ xml_copy_bottom_recurse(cxobj *x0t,
cvi = NULL;
/* Iterate over individual keys */
while ((cvi = cvec_each(cvk, cvi)) != NULL) {
keyname = cv_string_get(cvi);
keyname = cv_string_get(cvi);
if ((x0k = xml_find_type(x0, NULL, keyname, CX_ELMNT)) != NULL){
if ((x1k = xml_new(keyname, x1, CX_ELMNT)) == NULL)
goto done;
if (xml_copy(x0k, x1k) < 0)
if (xml_copy(x0k, x1k) < 0)
goto done;
}
@ -213,7 +213,7 @@ xml_copy_bottom_recurse(cxobj *x0t,
* @retval -1 General error, check specific clicon_errno, clicon_suberrno
*/
static int
xml_copy_from_bottom(cxobj *x0t,
xml_copy_from_bottom(cxobj *x0t,
cxobj *x0,
cxobj *x1t)
{
@ -222,7 +222,7 @@ xml_copy_from_bottom(cxobj *x0t,
cxobj *x0p = NULL;
cxobj *x1 = NULL;
yang_stmt *y = NULL;
if (x0 == x0t)
goto ok;
x0p = xml_parent(x0);
@ -309,7 +309,7 @@ text_read_modstate(clicon_handle h,
if (clixon_xml_parse_string("<module-set xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\"/>",
YB_NONE, yspec, &msdiff->md_diff, NULL) < 0)
goto done;
if (xml_rootchild(msdiff->md_diff, 0, &msdiff->md_diff) < 0)
if (xml_rootchild(msdiff->md_diff, 0, &msdiff->md_diff) < 0)
goto done;
if (!rfc7895){
@ -366,7 +366,7 @@ text_read_modstate(clicon_handle h,
continue; /* ignore other tags, such as module-set-id */
if ((name = xml_find_body(xs, "name")) == NULL)
continue;
/* 4a) If there is no such module in the file -> add to list mark as ADD */
/* 4a) If there is no such module in the file -> add to list mark as ADD */
if ((xf = xpath_first(xmodfile, NULL, "module[name=\"%s\"]", name)) == NULL){
if ((xs2 = xml_dup(xs)) == NULL) /* Make a copy of this modstate */
goto done;
@ -430,7 +430,7 @@ disable_nacm_on_empty(cxobj *xt,
goto done;
if (len){
if ((xb = xml_body_get(vec[0])) == NULL)
goto done;
goto done;
if (xml_value_set(xb, "false") < 0)
goto done;
}
@ -500,12 +500,12 @@ xmldb_readfile(clicon_handle h,
clicon_err(OE_CFG, ENOENT, "No CLICON_XMLDB_FORMAT");
goto done;
}
clicon_debug(CLIXON_DBG_DEFAULT, "Reading datastore %s using %s", dbfile, format);
clixon_debug(CLIXON_DBG_DEFAULT, "Reading datastore %s using %s", dbfile, format);
/* Parse file into internal XML tree from different formats */
if ((fp = fopen(dbfile, "r")) == NULL) {
clicon_err(OE_UNIX, errno, "open(%s)", dbfile);
goto done;
}
}
/* Read whole datastore file on the form:
* <config>
* modstate* # this is analyzed, stripped and returned as msdiff in text_read_modstate
@ -513,7 +513,7 @@ xmldb_readfile(clicon_handle h,
* </config>
* ret == 0 should not happen with YB_NONE. Binding is done later */
if (strcmp(format, "json")==0){
if (clixon_json_parse_file(fp, 1, YB_NONE, yspec, &x0, xerr) < 0)
if (clixon_json_parse_file(fp, 1, YB_NONE, yspec, &x0, xerr) < 0)
goto done;
}
else {
@ -525,12 +525,12 @@ xmldb_readfile(clicon_handle h,
* To ensure that, deal with two cases:
* 1. File is empty <top/> -> rename top-level to "config"
*/
if (xml_child_nr(x0) == 0){
if (xml_child_nr(x0) == 0){
if (xml_name_set(x0, DATASTORE_TOP_SYMBOL) < 0)
goto done;
goto done;
}
/* 2. File is not empty <top><config>...</config></top> -> replace root */
else{
else{
/* There should only be one element and called config */
if (singleconfigroot(x0, &x0) < 0)
goto done;
@ -666,11 +666,11 @@ xmldb_readfile(clicon_handle h,
* The function returns a minimal tree that includes all sub-trees that match
* xpath.
* This is a clixon datastore plugin of the the xmldb api
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] db Name of database to search in (filename including dir path
* @param[in] yb How to bind yang to XML top-level when parsing
* @param[in] nsc External XML namespace context, or NULL
* @param[in] xpath String with XPATH syntax. or NULL for all
* @param[in] xpath String with XPath syntax. or NULL for all
* @param[in] wdef With-defaults parameter, see RFC 6243
* @param[out] xret Single return XML tree. Free with xml_free()
* @param[out] msdiff If set, return modules-state differences
@ -683,7 +683,7 @@ xmldb_readfile(clicon_handle h,
*/
static int
xmldb_get_nocache(clicon_handle h,
const char *db,
const char *db,
yang_bind yb,
cvec *nsc,
const char *xpath,
@ -712,8 +712,7 @@ xmldb_get_nocache(clicon_handle h,
goto done;
if (ret == 0)
goto fail;
clicon_db_elmnt_set(h, db, &de0); /* Content is copied */
clicon_db_elmnt_set(h, db, &de0); /* Content is copied */
/* Here xt looks like: <config>...</config> */
/* Given the xpath, return a vector of matches in xvec */
if (xpath_vec(xt, nsc, "%s", &xvec, &xlen, xpath?xpath:"/") < 0)
@ -757,7 +756,7 @@ xmldb_get_nocache(clicon_handle h,
goto done;
if (xml_tree_prune_flags(xt, XML_FLAG_MARK, XML_FLAG_MARK)
< 0)
goto done;
goto done;
if (xml_defaults_nopresence(xt, 1) < 0)
goto done;
break;
@ -802,7 +801,7 @@ xmldb_get_nocache(clicon_handle h,
if (xml_apply0(xt, -1, xml_sort_verify, NULL) < 0)
clicon_log(LOG_NOTICE, "%s: sort verify failed #2", __FUNCTION__);
#endif
if (clicon_debug_get()>1)
if (clixon_debug_get()>1)
if (clixon_xml2file(stderr, xt, 0, 1, NULL, fprintf, 0, 0) < 0)
goto done;
*xtop = xt;
@ -826,11 +825,11 @@ xmldb_get_nocache(clicon_handle h,
* The function returns a minimal tree that includes all sub-trees that match
* xpath.
* This is a clixon datastore plugin of the the xmldb api
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] db Name of database to search in (filename including dir path
* @param[in] yb How to bind yang to XML top-level when parsing
* @param[in] nsc External XML namespace context, or NULL
* @param[in] xpath String with XPATH syntax. or NULL for all
* @param[in] xpath String with XPath syntax. or NULL for all
* @param[in] wdef With-defaults parameter, see RFC 6243
* @param[out] xtop Single return XML tree. Free with xml_free()
* @param[out] msdiff If set, return modules-state differences
@ -843,7 +842,7 @@ xmldb_get_nocache(clicon_handle h,
*/
static int
xmldb_get_cache(clicon_handle h,
const char *db,
const char *db,
yang_bind yb,
cvec *nsc,
const char *xpath,
@ -877,7 +876,7 @@ xmldb_get_cache(clicon_handle h,
goto done;
if (ret == 0)
goto fail;
/* Should we validate file if read from disk?
/* Should we validate file if read from disk?
* No, argument against: we may want to have a semantically wrong file and wish to edit?
*/
de0.de_xml = x0t;
@ -917,9 +916,8 @@ xmldb_get_cache(clicon_handle h,
/* Make new tree by copying top-of-tree from x0t to x1t */
if ((x1t = xml_new(xml_name(x0t), NULL, CX_ELMNT)) == NULL)
goto done;
xml_flag_set(x1t, XML_FLAG_TOP);
xml_flag_set(x1t, XML_FLAG_TOP);
xml_spec_set(x1t, xml_spec(x0t));
if (xlen < 1000){
/* This is optimized for the case when the tree is large and xlen is small
* If the tree is large and xlen too, then the other is better.
@ -960,7 +958,7 @@ xmldb_get_cache(clicon_handle h,
goto done;
if (xml_tree_prune_flags(x1t, XML_FLAG_MARK, XML_FLAG_MARK)
< 0)
goto done;
goto done;
if (xml_defaults_nopresence(x1t, 1) < 0)
goto done;
break;
@ -1000,11 +998,11 @@ xmldb_get_cache(clicon_handle h,
if (disable_nacm_on_empty(x1t, yspec) < 0)
goto done;
}
clicon_debug_xml(CLIXON_DBG_DETAIL, x1t, "%s", __FUNCTION__);
clixon_debug_xml(CLIXON_DBG_DETAIL, x1t, "%s", __FUNCTION__);
*xtop = x1t;
retval = 1;
done:
clicon_debug(CLIXON_DBG_DETAIL, "%s retval:%d", __FUNCTION__, retval);
clixon_debug(CLIXON_DBG_DETAIL, "%s retval:%d", __FUNCTION__, retval);
if (xvec)
free(xvec);
return retval;
@ -1017,11 +1015,11 @@ xmldb_get_cache(clicon_handle h,
*
* Useful for some higer level usecases for optimized access
* This is a clixon datastore plugin of the the xmldb api
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] db Name of database to search in (filename including dir path
* @param[in] yb How to bind yang to XML top-level when parsing
* @param[in] nsc External XML namespace context, or NULL
* @param[in] xpath String with XPATH syntax. or NULL for all
* @param[in] xpath String with XPath syntax. or NULL for all
* @param[in] wdef With-defaults parameter, see RFC 6243
* @param[out] xret Single return XML tree. Free with xml_free()
* @param[out] msdiff If set, return modules-state differences
@ -1033,7 +1031,7 @@ xmldb_get_cache(clicon_handle h,
*/
static int
xmldb_get_zerocopy(clicon_handle h,
const char *db,
const char *db,
yang_bind yb,
cvec *nsc,
const char *xpath,
@ -1107,9 +1105,8 @@ xmldb_get_zerocopy(clicon_handle h,
/* Mark and remove nodes having schema default values */
if (xml_apply(x0t, CX_ELMNT, (xml_applyfn_t*) xml_flag_default_value, (void*) XML_FLAG_MARK) < 0)
goto done;
if (xml_tree_prune_flags(x0t, XML_FLAG_MARK, XML_FLAG_MARK)
< 0)
goto done;
if (xml_tree_prune_flags(x0t, XML_FLAG_MARK, XML_FLAG_MARK) < 0)
goto done;
if (xml_defaults_nopresence(x0t, 1) < 0)
goto done;
break;
@ -1150,13 +1147,13 @@ xmldb_get_zerocopy(clicon_handle h,
if (disable_nacm_on_empty(x0t, yspec) < 0)
goto done;
}
if (clicon_debug_get() > 1)
if (clixon_debug_get() > 1)
if (clixon_xml2file(stderr, x0t, 0, 1, NULL, fprintf, 0, 0) < 0)
goto done;
*xtop = x0t;
retval = 1;
done:
clicon_debug(CLIXON_DBG_DETAIL, "%s retval:%d", __FUNCTION__, retval);
clixon_debug(CLIXON_DBG_DETAIL, "%s retval:%d", __FUNCTION__, retval);
if (xvec)
free(xvec);
return retval;
@ -1167,10 +1164,10 @@ xmldb_get_zerocopy(clicon_handle h,
/*! Get content of datastore and return a copy of the XML tree
*
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] db Name of database to search in, eg "running"
* @param[in] nsc XML namespace context for XPATH
* @param[in] xpath String with XPATH syntax. or NULL for all
* @param[in] nsc XML namespace context for XPath
* @param[in] xpath String with XPath syntax. or NULL for all
* @param[out] xret Single return XML tree. Free with xml_free()
* @retval 1 OK
* @retval 0 Parse OK but yang assigment not made (or only partial) and xerr set
@ -1183,9 +1180,9 @@ xmldb_get_zerocopy(clicon_handle h,
* @endcode
* @see xmldb_get0 Underlying more capable API for enabling zero-copy
*/
int
xmldb_get(clicon_handle h,
const char *db,
int
xmldb_get(clicon_handle h,
const char *db,
cvec *nsc,
char *xpath,
cxobj **xret)
@ -1201,11 +1198,11 @@ xmldb_get(clicon_handle h,
* appropriately.
* The tree returned may be the actual cache, therefore calls for cleaning and
* freeing tree must be made after use.
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] db Name of datastore, eg "running"
* @param[in] yb How to bind yang to XML top-level when parsing (if YB_NONE, no defaults)
* @param[in] nsc External XML namespace context, or NULL
* @param[in] xpath String with XPATH syntax. or NULL for all
* @param[in] xpath String with XPath syntax. or NULL for all
* @param[in] copy Force copy. Overrides cache_zerocopy -> cache
* @param[in] wdef With-defaults parameter, see RFC 6243
* @param[out] xret Single return XML tree. Free with xml_free()
@ -1244,9 +1241,9 @@ xmldb_get(clicon_handle h,
* (the existing tree is discarded), the default (empty) xml tree is:
* <c><x>0</x></c>
*/
int
int
xmldb_get0(clicon_handle h,
const char *db,
const char *db,
yang_bind yb,
cvec *nsc,
const char *xpath,
@ -1294,19 +1291,19 @@ xmldb_get0(clicon_handle h,
/*! Clear cached xml tree obtained with xmldb_get0, if zerocopy
*
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] db Name of datastore
* @retval 0 OK
* @retval -1 General error, check specific clicon_errno, clicon_suberrno
* @note "Clear" an xml tree means removing default values and resetting all flags.
* @see xmldb_get0
*/
int
xmldb_get0_clear(clicon_handle h,
int
xmldb_get0_clear(clicon_handle h,
cxobj *x)
{
int retval = -1;
if (x == NULL)
goto ok;
/* Remove global defaults and empty non-presence containers */
@ -1328,11 +1325,11 @@ xmldb_get0_clear(clicon_handle h,
*
* @param[in] h Clixon handle
* @param[in,out] xp Pointer to XML cache.
* @retval 0 Always.
* @retval 0 Always.
* @see xmldb_get0
*/
int
xmldb_get0_free(clicon_handle h,
int
xmldb_get0_free(clicon_handle h,
cxobj **xp)
{
if (*xp == NULL)

View file

@ -112,7 +112,7 @@ attr_ns_value(cxobj *x,
char *val = NULL;
/* prefix=NULL since we do not know the prefix */
if ((xa = xml_find_type(x, NULL, name, CX_ATTR)) != NULL){
if ((xa = xml_find_type(x, NULL, name, CX_ATTR)) != NULL){
if (xml2ns(xa, xml_prefix(xa), &ans) < 0)
goto done;
if (ans == NULL){ /* the attribute exists, but no namespace */
@ -159,11 +159,11 @@ attr_ns_value(cxobj *x,
*/
static int
check_body_namespace(cxobj *x0,
cxobj *x0p,
cxobj *x0p,
cxobj *x1,
char *x1bstr,
yang_stmt *y,
cbuf *cbret)
cbuf *cbret)
{
int retval = -1;
char *prefix = NULL;
@ -187,7 +187,7 @@ check_body_namespace(cxobj *x0,
goto done;
if (ns0 != NULL && ns1 != NULL){ /* namespace exists in both x1 and x0 */
if (strcmp(ns0, ns1)){
/* prefixes in x1 and x0 refers to different namespaces
/* prefixes in x1 and x0 refers to different namespaces
* XXX return netconf error instead bad-attribue?
*/
if ((cberr = cbuf_new()) == NULL){
@ -294,7 +294,7 @@ check_when_condition(cxobj *x0p,
if ((y = y0) != NULL ||
(y = (yang_stmt*)xml_spec(x1)) != NULL){
if ((xpath = yang_when_xpath_get(y)) != NULL){
if ((xpath = yang_when_xpath_get(y)) != NULL){
nsc = yang_when_nsc_get(y);
x1p = xml_parent(x1);
if ((nr = xpath_vec_bool(x1p, nsc, "%s", xpath)) < 0) /* Try request */
@ -398,7 +398,7 @@ choice_delete_other(cxobj *x0,
yang_stmt *y0choice;
yang_stmt *y1case = NULL;
yang_stmt *y1choice = NULL;
if (choice_case_get(y1c, &y1case, &y1choice) == 0)
goto ok;
x0prev = NULL;
@ -430,7 +430,7 @@ choice_delete_other(cxobj *x0,
/*! Modify a base tree x0 with x1 with yang spec y according to operation op
*
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] x0 Base xml tree (can be NULL in add scenarios)
* @param[in] x0p Parent of x0
* @param[in] x0t Top level of existing tree, eg needed for NACM rules
@ -485,7 +485,7 @@ text_modify(clicon_handle h,
enum insert_type insert = INS_LAST;
int changed = 0; /* Only if x0p's children have changed-> sort necessary */
cvec *nscx1 = NULL;
char *createstr = NULL;
char *createstr = NULL;
yang_stmt *yrestype = NULL;
char *restype;
int ismount = 0;
@ -521,7 +521,7 @@ text_modify(clicon_handle h,
/* RFC 8040 4.6 PATCH:
* If the target resource instance does not exist, the server MUST NOT create it.
*/
if (netconf_data_missing(cbret,
if (netconf_data_missing(cbret,
"RFC 8040 4.6. PATCH: If the target resource instance does not exist, the server MUST NOT create it") < 0)
goto done;
goto fail;
@ -541,9 +541,9 @@ text_modify(clicon_handle h,
if (yang_keyword_get(y0) == Y_LEAF_LIST ||
yang_keyword_get(y0) == Y_LEAF){
/* This is a check that a leaf does not have sub-elements
/* This is a check that a leaf does not have sub-elements
* such as: <leaf>a <leaf>b</leaf> </leaf>
*/
*/
if (xml_child_nr_type(x1, CX_ELMNT)){
if (netconf_unknown_element(cbret, "application", x1name, "Leaf contains sub-element") < 0)
goto done;
@ -576,7 +576,7 @@ text_modify(clicon_handle h,
}
}
x1bstr = xml_body(x1);
switch(op){
switch(op){
case OP_CREATE:
if (x0){
if (netconf_data_exists(cbret, "Data already exists; cannot create new resource") < 0)
@ -590,7 +590,7 @@ text_modify(clicon_handle h,
* of ordered-by user and (changed) insert attribute.
*/
if (!permit && xnacm){
if ((ret = nacm_datanode_write(h, x1, x1t, x0?NACM_UPDATE:NACM_CREATE, username, xnacm, cbret)) < 0)
if ((ret = nacm_datanode_write(h, x1, x1t, x0?NACM_UPDATE:NACM_CREATE, username, xnacm, cbret)) < 0)
goto done;
if (ret == 0)
goto fail;
@ -607,7 +607,7 @@ text_modify(clicon_handle h,
case OP_NONE: /* fall thru */
if (x0==NULL){
if ((op != OP_NONE) && !permit && xnacm){
if ((ret = nacm_datanode_write(h, x1, x1t, NACM_CREATE, username, xnacm, cbret)) < 0)
if ((ret = nacm_datanode_write(h, x1, x1t, NACM_CREATE, username, xnacm, cbret)) < 0)
goto done;
if (ret == 0)
goto fail;
@ -632,7 +632,7 @@ text_modify(clicon_handle h,
xml_flag_set(x0, XML_FLAG_NONE); /* Mark for potential deletion */
if (x1bstr){ /* empty type does not have body */ /* XXX Here x0 = <b></b> */
if ((x0b = xml_new("body", x0, CX_BODY)) == NULL)
goto done;
goto done;
}
}
/* Some bodies (eg identityref) requires proper namespace setup, so a type lookup is
@ -650,7 +650,7 @@ text_modify(clicon_handle h,
x1bstr="";
if (x1bstr){
if (strcmp(restype, "identityref") == 0){
x1bstr = clixon_trim2(x1bstr, " \t\n");
x1bstr = clixon_trim2(x1bstr, " \t\n");
if ((ret = check_body_namespace(x0, x0p, x1, x1bstr, y0, cbret)) < 0)
goto done;
if (ret == 0)
@ -660,7 +660,7 @@ text_modify(clicon_handle h,
/* Some bodies strip pretty-printed here, unsure where to do this,.. */
if (strcmp(restype, "enumeration") == 0 ||
strcmp(restype, "bits") == 0)
x1bstr = clixon_trim2(x1bstr, " \t\n");
x1bstr = clixon_trim2(x1bstr, " \t\n");
#if 0 /* Passes regression test without, keep for some time until other test requires it */
/* If origin body has namespace definitions, copy them. The reason is that
* some bodies rely on namespace prefixes, such as NACM path, but there is
@ -700,8 +700,8 @@ text_modify(clicon_handle h,
if (xml_creator_add(x0, creator) < 0)
goto done;
}
if (changed){
if (xml_insert(x0p, x0, insert, valstr, NULL) < 0)
if (changed){
if (xml_insert(x0p, x0, insert, valstr, NULL) < 0)
goto done;
}
break;
@ -719,7 +719,7 @@ text_modify(clicon_handle h,
if (ret == 0)
goto fail;
}
x0bstr = xml_body(x0);
x0bstr = xml_body(x0);
/* Purge if x1 value is NULL(match-all) or both values are equal */
if ((x1bstr == NULL) ||
((x0bstr=xml_body(x0)) != NULL && strcmp(x0bstr, x1bstr)==0)){
@ -774,7 +774,7 @@ text_modify(clicon_handle h,
if (keystr && xml_nsctx_node(x1, &nscx1) < 0)
goto done;
}
switch(op){
switch(op){
case OP_CREATE:
if (x0){
if (xml_defaults_nopresence(x0, 0) == 0){
@ -784,13 +784,13 @@ text_modify(clicon_handle h,
}
}
case OP_REPLACE: /* fall thru */
case OP_MERGE:
case OP_MERGE:
if (!(op == OP_MERGE && instr==NULL)){
/* Remove existing, also applies to merge in the special case
* of ordered-by user and (changed) insert attribute.
*/
if (!permit && xnacm){
if ((ret = nacm_datanode_write(h, x1, x1t, x0?NACM_UPDATE:NACM_CREATE, username, xnacm, cbret)) < 0)
if ((ret = nacm_datanode_write(h, x1, x1t, x0?NACM_UPDATE:NACM_CREATE, username, xnacm, cbret)) < 0)
goto done;
if (ret == 0)
goto fail;
@ -816,7 +816,7 @@ text_modify(clicon_handle h,
if (op == OP_NONE)
break;
if (op==OP_MERGE && !permit && xnacm){
if ((ret = nacm_datanode_write(h, x1, x1t, x0?NACM_UPDATE:NACM_CREATE, username, xnacm, cbret)) < 0)
if ((ret = nacm_datanode_write(h, x1, x1t, x0?NACM_UPDATE:NACM_CREATE, username, xnacm, cbret)) < 0)
goto done;
if (ret == 0)
goto fail;
@ -833,7 +833,7 @@ text_modify(clicon_handle h,
} /* anyxml, anydata */
if (x0==NULL){
if (op==OP_MERGE && !permit && xnacm){
if ((ret = nacm_datanode_write(h, x1, x1t, NACM_CREATE, username, xnacm, cbret)) < 0)
if ((ret = nacm_datanode_write(h, x1, x1t, NACM_CREATE, username, xnacm, cbret)) < 0)
goto done;
if (ret == 0)
goto fail;
@ -868,9 +868,9 @@ text_modify(clicon_handle h,
clicon_err(OE_UNIX, errno, "calloc");
goto done;
}
x1c = NULL;
x1c = NULL;
i = 0;
while ((x1c = xml_child_each(x1, x1c, CX_ELMNT)) != NULL) {
while ((x1c = xml_child_each(x1, x1c, CX_ELMNT)) != NULL) {
x1cname = xml_name(x1c);
/* Get yang spec of the child by child matching */
if ((yc = yang_find_datanode(y0, x1cname)) == NULL){
@ -968,7 +968,7 @@ text_modify(clicon_handle h,
case OP_REMOVE: /* fall thru */
if (x0){
if (!permit && xnacm){
if ((ret = nacm_datanode_write(h, x0, x0t, NACM_DELETE, username, xnacm, cbret)) < 0)
if ((ret = nacm_datanode_write(h, x0, x0t, NACM_DELETE, username, xnacm, cbret)) < 0)
goto done;
if (ret == 0)
goto fail;
@ -1010,7 +1010,7 @@ text_modify(clicon_handle h,
/*! Modify a top-level base tree x0 with modification tree x1
*
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] x0t Base xml tree (can be NULL in add scenarios)
* @param[in] x1t XML tree which modifies base
* @param[in] yspec Top-level yang spec (if y is NULL)
@ -1044,7 +1044,7 @@ text_modify_top(clicon_handle h,
char *opstr = NULL;
int ret;
char *createstr = NULL;
/* Check for operations embedded in tree according to netconf */
if ((ret = attr_ns_value(x1t,
"operation", NETCONF_BASE_NAMESPACE,
@ -1060,9 +1060,9 @@ text_modify_top(clicon_handle h,
if (ret == 0)
goto fail;
/* Special case if incoming x1t is empty, top-level only <config/> */
if (xml_child_nr_type(x1t, CX_ELMNT) == 0){
if (xml_child_nr_type(x1t, CX_ELMNT) == 0){
if (xml_child_nr_type(x0t, CX_ELMNT)){ /* base tree not empty */
switch(op){
switch(op){
case OP_DELETE:
case OP_REMOVE:
case OP_REPLACE:
@ -1082,7 +1082,7 @@ text_modify_top(clicon_handle h,
}
}
else /* base tree empty */
switch(op){
switch(op){
#if 0 /* According to RFC6020 7.5.8 you cant delete a non-existing object.
On the other hand, the top-level cannot be removed anyway.
Additionally, I think this is irritating so I disable it.
@ -1107,7 +1107,7 @@ text_modify_top(clicon_handle h,
clicon_data_set(h, "objectexisted", "false");
}
if (!permit && xnacm){
if ((ret = nacm_datanode_write(h, x1t, x1t, NACM_UPDATE, username, xnacm, cbret)) < 0)
if ((ret = nacm_datanode_write(h, x1t, x1t, NACM_UPDATE, username, xnacm, cbret)) < 0)
goto done;
if (ret == 0)
goto fail;
@ -1200,7 +1200,7 @@ text_modify_top(clicon_handle h,
*/
int
xmldb_put(clicon_handle h,
const char *db,
const char *db,
enum operation_type op,
cxobj *x1,
char *username,
@ -1268,7 +1268,7 @@ xmldb_put(clicon_handle h,
/* Here assume if xnacm is set and !permit do NACM */
clicon_data_del(h, "objectexisted");
/*
/*
* Modify base tree x with modification x1. This is where the
* new tree is made.
*/
@ -1287,7 +1287,7 @@ xmldb_put(clicon_handle h,
/* Remove NONE nodes if all subs recursively are also NONE */
if (xml_tree_prune_flagged_sub(x0, XML_FLAG_NONE, 0, NULL) <0)
goto done;
if (xml_apply(x0, CX_ELMNT, (xml_applyfn_t*)xml_flag_reset,
if (xml_apply(x0, CX_ELMNT, (xml_applyfn_t*)xml_flag_reset,
(void*)(XML_FLAG_NONE|XML_FLAG_MARK)) < 0)
goto done;
/* Remove global defaults and empty non-presence containers */
@ -1330,7 +1330,7 @@ xmldb_put(clicon_handle h,
if ((f = fopen(dbfile, "w")) == NULL){
clicon_err(OE_CFG, errno, "Creating file %s", dbfile);
goto done;
}
}
pretty = clicon_option_bool(h, "CLICON_XMLDB_PRETTY");
if (strcmp(format,"json")==0){
if (clixon_json2file(f, x0, pretty, fprintf, 0, 0) < 0)
@ -1374,7 +1374,7 @@ xmldb_dump(clicon_handle h,
cxobj *xmodst = NULL;
char *format;
int pretty;
/* clear XML tree of defaults */
if (xml_tree_prune_flagged(xt, XML_FLAG_DEFAULT, 1) < 0)
goto done;

View file

@ -181,8 +181,8 @@ split_path_free(char **list,
}
/*! Find a peer of this node by name
* search through the list pointed at by peer
*
* search through the list pointed at by peer
* @param[in] node Pointer to a node in the peer list
* @param[in] node_name Name of node we're looking for
* @retval pointer Pointer to found node or NULL
@ -192,7 +192,7 @@ static dispatcher_entry_t *
find_peer(dispatcher_entry_t *node, char *node_name)
{
dispatcher_entry_t *i;
if ((node == NULL) || (node_name == NULL)) {
/* protect against idiot users */
return NULL;
@ -226,7 +226,6 @@ add_peer_node(dispatcher_entry_t *node,
if ((new_node = malloc(sizeof(dispatcher_entry_t))) == NULL)
return NULL;
memset(new_node, 0, sizeof(dispatcher_entry_t));
if (node == NULL) {
/* this is a new node */
@ -336,7 +335,6 @@ get_entry(dispatcher_entry_t *root,
/* clean up */
split_path_free(split_path_list, split_path_len);
return best;
}

View file

@ -199,6 +199,8 @@ find_category(int category)
* @param[in] category Clixon error category, See enum clicon_err
* @param[in] suberr Error number, typically errno
* @param[in] format Error string, format with argv
* @retval 0 OK
* @retval -1 Error
* @see clicon_err_reset Reset the global error variables.
*/
int
@ -206,14 +208,14 @@ clicon_err_fn(const char *fn,
const int line,
int category,
int suberr,
const char *format, ...)
const char *format, ...)
{
int retval = -1;
va_list args;
int len;
char *msg = NULL;
int retval = -1;
struct clixon_err_cats *cec;
/* Set the global variables */
clicon_errno = category;
clicon_suberrno = suberr;
@ -267,27 +269,27 @@ clicon_err_fn(const char *fn,
else if (suberr){ /* Actually log it */
/* Here we could take care of specific errno, like application-defined errors */
if (fn)
clicon_log(LOG_ERR, "%s: %d: %s: %s: %s",
clicon_log(LOG_ERR, "%s: %d: %s: %s: %s",
fn,
line,
clicon_strerror(category),
msg,
suberr==XMLPARSE_ERRNO?"XML parse error":strerror(suberr));
else
clicon_log(LOG_ERR, "%s: %s: %s",
clicon_log(LOG_ERR, "%s: %s: %s",
clicon_strerror(category),
msg,
suberr==XMLPARSE_ERRNO?"XML parse error":strerror(suberr));
}
else{
if (fn)
clicon_log(LOG_ERR, "%s: %d: %s: %s",
clicon_log(LOG_ERR, "%s: %d: %s: %s",
fn,
line,
clicon_strerror(category),
msg);
else
clicon_log(LOG_ERR, "%s: %s",
clicon_log(LOG_ERR, "%s: %s",
clicon_strerror(category),
msg);
}
@ -357,7 +359,7 @@ clixon_err_cat_reg(enum clicon_err category,
cec->cec_category = category;
cec->cec_handle = handle;
cec->cec_logfn = logfn;
INSQ(cec, _err_cat_list);
INSQ(cec, _err_cat_list);
return 0;
}
@ -369,6 +371,6 @@ clixon_err_exit(void)
while ((cec = _err_cat_list) != NULL){
DELQ(cec, _err_cat_list, clixon_err_cats *);
free(cec);
}
}
return 0;
}

View file

@ -102,6 +102,7 @@ static int _clicon_sig_child = 0;
static int _clicon_sig_ignore = 0;
/*! For signal handlers: instead of doing exit, set a global variable to exit
*
* - zero means dont exit,
* - one means exit,
* - more than one means decrement and make another event loop
@ -175,9 +176,9 @@ clicon_sig_ignore_get(void)
* @see clixon_event_unreg_fd
*/
int
clixon_event_reg_fd(int fd,
int (*fn)(int, void*),
void *arg,
clixon_event_reg_fd(int fd,
int (*fn)(int, void*),
void *arg,
char *str)
{
struct event_data *e;
@ -194,23 +195,27 @@ clixon_event_reg_fd(int fd,
e->e_type = EVENT_FD;
e->e_next = ee;
ee = e;
clicon_debug(CLIXON_DBG_DETAIL, "%s, registering %s", __FUNCTION__, e->e_string);
clixon_debug(CLIXON_DBG_DETAIL, "%s, registering %s", __FUNCTION__, e->e_string);
return 0;
}
/*! Deregister a file descriptor callback
*
* @param[in] s File descriptor
* @param[in] fn Function to call when input available on fd
* @retval 0 OK
* @retval -1 Error
* Note: deregister when exactly function and socket match, not argument
* @see clixon_event_reg_fd
* @see clixon_event_unreg_timeout
*/
int
clixon_event_unreg_fd(int s,
clixon_event_unreg_fd(int s,
int (*fn)(int, void*))
{
struct event_data *e, **e_prev;
int found = 0;
struct event_data *e;
struct event_data **e_prev;
int found = 0;
e_prev = &ee;
for (e = ee; e; e = e->e_next){
@ -232,6 +237,8 @@ clixon_event_unreg_fd(int s,
* @param[in] fn Function to call at time t
* @param[in] arg Argument to function fn
* @param[in] str Describing string for logging
* @retval 0 OK
* @retval -1 Error
* @code
* int fn(int d, void *arg){
* struct timeval t, t1;
@ -249,9 +256,9 @@ clixon_event_unreg_fd(int s,
* @see clixon_event_unreg_timeout
*/
int
clixon_event_reg_timeout(struct timeval t,
int (*fn)(int, void*),
void *arg,
clixon_event_reg_timeout(struct timeval t,
int (*fn)(int, void*),
void *arg,
char *str)
{
int retval = -1;
@ -282,13 +289,14 @@ clixon_event_reg_timeout(struct timeval t,
}
e->e_next = e1;
*e_prev = e;
clicon_debug(CLIXON_DBG_DETAIL, "%s: %s", __FUNCTION__, str);
clixon_debug(CLIXON_DBG_DETAIL, "%s: %s", __FUNCTION__, str);
retval = 0;
done:
return retval;
}
/*! Deregister a timeout callback as previosly registered by clixon_event_reg_timeout()
*
* Note: deregister when exactly function and function arguments match, not time. So you
* cannot have same function and argument callback on different timeouts. This is a little
* different from clixon_event_unreg_fd.
@ -300,7 +308,7 @@ clixon_event_reg_timeout(struct timeval t,
* @see clixon_event_unreg_fd
*/
int
clixon_event_unreg_timeout(int (*fn)(int, void*),
clixon_event_unreg_timeout(int (*fn)(int, void*),
void *arg)
{
struct event_data *e, **e_prev;
@ -320,12 +328,13 @@ clixon_event_unreg_timeout(int (*fn)(int, void*),
}
/*! Poll to see if there is any data available on this file descriptor.
*
* @param[in] fd File descriptor
* @retval -1 Error
* @retval 0 Nothing to read/empty fd
* @retval 1 Something to read on fd
* @retval 0 Nothing to read/empty fd
* @retval -1 Error
*/
int
int
clixon_event_poll(int fd)
{
int retval = -1;
@ -373,11 +382,11 @@ clixon_event_loop(clicon_handle h)
FD_SET(e->e_fd, &fdset);
if (ee_timers != NULL){
gettimeofday(&t0, NULL);
timersub(&ee_timers->e_time, &t0, &t);
timersub(&ee_timers->e_time, &t0, &t);
if (t.tv_sec < 0)
n = select(FD_SETSIZE, &fdset, NULL, NULL, &tnull);
n = select(FD_SETSIZE, &fdset, NULL, NULL, &tnull);
else
n = select(FD_SETSIZE, &fdset, NULL, NULL, &t);
n = select(FD_SETSIZE, &fdset, NULL, NULL, &t);
}
else
n = select(FD_SETSIZE, &fdset, NULL, NULL, NULL);
@ -396,7 +405,7 @@ clixon_event_loop(clicon_handle h)
* New select loop is called
* (3) Other signals result in an error and return -1.
*/
clicon_debug(1, "%s select: %s", __FUNCTION__, strerror(errno));
clixon_debug(CLIXON_DBG_DEFAULT, "%s select: %s", __FUNCTION__, strerror(errno));
if (clixon_exit_get() == 1){
clicon_err(OE_EVENTS, errno, "select");
retval = 0;
@ -422,7 +431,7 @@ clixon_event_loop(clicon_handle h)
if (n==0){ /* Timeout */
e = ee_timers;
ee_timers = ee_timers->e_next;
clicon_debug(CLIXON_DBG_DETAIL, "%s timeout: %s", __FUNCTION__, e->e_string);
clixon_debug(CLIXON_DBG_DETAIL, "%s timeout: %s", __FUNCTION__, e->e_string);
if ((*e->e_fn)(0, e->e_arg) < 0){
free(e);
goto err;
@ -436,9 +445,9 @@ clixon_event_loop(clicon_handle h)
}
e_next = e->e_next;
if(e->e_type == EVENT_FD && FD_ISSET(e->e_fd, &fdset)){
clicon_debug(CLIXON_DBG_DETAIL, "%s: FD_ISSET: %s", __FUNCTION__, e->e_string);
clixon_debug(CLIXON_DBG_DETAIL, "%s: FD_ISSET: %s", __FUNCTION__, e->e_string);
if ((*e->e_fn)(e->e_fd, e->e_arg) < 0){
clicon_debug(1, "%s Error in: %s", __FUNCTION__, e->e_string);
clixon_debug(CLIXON_DBG_DEFAULT, "%s Error in: %s", __FUNCTION__, e->e_string);
goto err;
}
if (_ee_unreg){
@ -450,12 +459,12 @@ clixon_event_loop(clicon_handle h)
clixon_exit_decr(); /* If exit is set and > 1, decrement it (and exit when 1) */
continue;
err:
clicon_debug(1, "%s err", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s err", __FUNCTION__);
break;
}
if (clixon_exit_get() == 1)
retval = 0;
clicon_debug(1, "%s done:%d", __FUNCTION__, retval);
clixon_debug(CLIXON_DBG_DEFAULT, "%s done:%d", __FUNCTION__, retval);
return retval;
}
@ -463,7 +472,7 @@ int
clixon_event_exit(void)
{
struct event_data *e, *e_next;
e_next = ee;
while ((e = e_next) != NULL){
e_next = e->e_next;

View file

@ -65,7 +65,7 @@
/*! qsort "compar" for directory alphabetically sorting, see qsort(3)
*/
static int
clicon_file_dirent_sort(const void* arg1,
clicon_file_dirent_sort(const void* arg1,
const void* arg2)
{
struct dirent *d1 = (struct dirent *)arg1;
@ -74,7 +74,8 @@ clicon_file_dirent_sort(const void* arg1,
return strcoll(d1->d_name, d2->d_name);
}
/*!
/*! List files recursive
*
* @param[in,out] cvv On the format: (name, path)*
*/
static int
@ -88,7 +89,7 @@ clicon_files_recursive1(const char *dir,
DIR *dirp = NULL;
int res = 0;
struct stat st;
if (dir == NULL){
clicon_err(OE_UNIX, EINVAL, "Requires dir != NULL");
goto done;
@ -98,7 +99,7 @@ clicon_files_recursive1(const char *dir,
if (dent->d_type == DT_DIR) {
/* If we find a directory we might want to enter it, unless it
is the current directory (.) or parent (..) */
if (strcmp(dent->d_name, ".") == 0 || strcmp(dent->d_name, "..") == 0)
if (strcmp(dent->d_name, ".") == 0 || strcmp(dent->d_name, "..") == 0)
continue;
/* Build the new directory and enter it. */
@ -143,8 +144,8 @@ clicon_files_recursive(const char *dir,
regex_t re = {0,};
int res = 0;
char errbuf[128];
clicon_debug(CLIXON_DBG_DETAIL, "%s dir:%s", __FUNCTION__, dir);
clixon_debug(CLIXON_DBG_DETAIL, "%s dir:%s", __FUNCTION__, dir);
if (regexp && (res = regcomp(&re, regexp, REG_EXTENDED)) != 0) {
regerror(res, &re, errbuf, sizeof(errbuf));
clicon_err(OE_DB, 0, "regcomp: %s", errbuf);
@ -165,7 +166,6 @@ clicon_files_recursive(const char *dir,
* @param[out] ent Entries pointer, will be filled in with dir entries. Free after use
* @param[in] regexp Regexp filename matching
* @param[in] type File type matching, see stat(2)
*
* @retval n Number of matching files in directory
* @retval -1 Error
*
@ -238,7 +238,7 @@ clicon_file_dirent(const char *dir,
clicon_err(OE_UNIX, errno, "realloc");
goto quit;
} /* realloc */
clicon_debug(CLIXON_DBG_DETAIL, "%s memcpy(%p %p %u", __FUNCTION__, &new[nent], dent, direntStructSize);
clixon_debug(CLIXON_DBG_DETAIL, "%s memcpy(%p %p %u", __FUNCTION__, &new[nent], dent, direntStructSize);
/* man (3) readdir:
* By implication, the use sizeof(struct dirent) to capture the size of the record including
* the size of d_name is also incorrect. */
@ -266,10 +266,10 @@ quit:
* @param[in] src Source filename
* @param[out] target Destination filename
* @retval 0 OK
* @retval -1 Error
* @retval -1 Error
*/
int
clicon_file_copy(char *src,
clicon_file_copy(char *src,
char *target)
{
int retval = -1;
@ -312,11 +312,11 @@ clicon_file_copy(char *src,
*
* @param[in] filename
* @param[out] cb
* @retval 0 OK
* @retval -1 Error
* @retval 0 OK
* @retval -1 Error
*/
int
clicon_file_cbuf(const char *filename,
clicon_file_cbuf(const char *filename,
cbuf *cb)
{
int retval = -1;

View file

@ -46,7 +46,7 @@
#include <string.h>
#include <assert.h>
#include <sys/time.h>
#include <cligen/cligen.h>
/* clicon */
@ -66,6 +66,7 @@
#define handle(h) (assert(clicon_handle_check(h)==0),(struct clicon_handle *)(h))
/*! Internal structure of basic handle. Also header of all other handles.
*
* @note If you change here, you must also change the structs below:
* This is the internal definition of a "Clixon handle" which in its external
* form is "clicon_handle" and is used in most Clixon API calls.
@ -96,13 +97,13 @@ struct clicon_handle {
/*! Internal call to allocate a CLICON handle.
*
* @param[in] size Size of handle (internal) struct.
* @retval h Clicon handle
* @retval h Clixon handle
*
* There may be different variants of handles with some common options.
* So far the only common options is a MAGIC cookie for sanity checks and
* CLICON options
*/
clicon_handle
clicon_handle
clicon_handle_init0(int size)
{
struct clicon_handle *ch;
@ -133,21 +134,24 @@ clicon_handle_init0(int size)
/*! Basic CLICON init functions returning a handle for API access.
*
* @retval h Clicon handle
* @retval h Clixon handle
* This is the first call to CLICON basic API which returns a handle to be
* used in the API functions. There are other clicon_init functions for more
* elaborate applications (cli/backend/netconf). This should be used by the most
* basic applications that use CLICON lib directly.
*/
clicon_handle
clicon_handle
clicon_handle_init(void)
{
return clicon_handle_init0(sizeof(struct clicon_handle));
}
/*! Deallocate clicon handle, including freeing handle data.
* @param[in] h Clicon handle
* @Note: handle 'h' cannot be used in calls after this
*
* @param[in] h Clixon handle
* @retval 0 OK
* @retval -1 Error
* @note: handle 'h' cannot be used in calls after this
*/
int
clicon_handle_exit(clicon_handle h)
@ -169,7 +173,8 @@ clicon_handle_exit(clicon_handle h)
}
/*! Check struct magic number for sanity checks
* @param[in] h Clicon handle
*
* @param[in] h Clixon handle
* @retval 0 Sanity check OK
* @retval -1 Sanity check failed
*/
@ -183,7 +188,8 @@ clicon_handle_check(clicon_handle h)
}
/*! Return clicon options (hash-array) given a handle.
* @param[in] h Clicon handle
*
* @param[in] h Clixon handle
*/
clicon_hash_t *
clicon_options(clicon_handle h)
@ -194,7 +200,8 @@ clicon_options(clicon_handle h)
}
/*! Return clicon data (hash-array) given a handle.
* @param[in] h Clicon handle
*
* @param[in] h Clixon handle
*/
clicon_hash_t *
clicon_data(clicon_handle h)
@ -205,7 +212,8 @@ clicon_data(clicon_handle h)
}
/*! Return clicon db_elmnt (hash-array) given a handle.
* @param[in] h Clicon handle
*
* @param[in] h Clixon handle
*/
clicon_hash_t *
clicon_db_elmnt(clicon_handle h)
@ -216,7 +224,8 @@ clicon_db_elmnt(clicon_handle h)
}
/*! Return stream hash-array given a clicon handle.
* @param[in] h Clicon handle
*
* @param[in] h Clixon handle
*/
event_stream_t *
clicon_stream(clicon_handle h)
@ -241,7 +250,7 @@ clicon_stream_append(clicon_handle h,
event_stream_t *es)
{
struct clicon_handle *ch = handle(h);
ADDQ(es, ch->ch_stream);
return 0;
}

View file

@ -98,7 +98,7 @@
#include "clixon_err.h"
#include "clixon_hash.h"
#define HASH_SIZE 1031 /* Number of hash buckets. Should be a prime */
#define HASH_SIZE 1031 /* Number of hash buckets. Should be a prime */
#define align4(s) (((s)/4)*4 + 4)
/*! A very simplistic algorithm to calculate a hash bucket index
@ -164,7 +164,7 @@ clicon_hash_free(clicon_hash_t *hash)
* @retval NULL Not found
*/
clicon_hash_t
clicon_hash_lookup(clicon_hash_t *hash,
clicon_hash_lookup(clicon_hash_t *hash,
const char *key)
{
uint32_t bkt;
@ -190,7 +190,7 @@ clicon_hash_lookup(clicon_hash_t *hash,
* @retval NULL Key not found or value NULL
*/
void *
clicon_hash_value(clicon_hash_t *hash,
clicon_hash_value(clicon_hash_t *hash,
const char *key,
size_t *vlen)
{
@ -220,15 +220,15 @@ clicon_hash_value(clicon_hash_t *hash,
* @note special case val is NULL and vlen==0
*/
clicon_hash_t
clicon_hash_add(clicon_hash_t *hash,
const char *key,
void *val,
clicon_hash_add(clicon_hash_t *hash,
const char *key,
void *val,
size_t vlen)
{
void *newval = NULL;
clicon_hash_t h;
clicon_hash_t new = NULL;
if (hash == NULL){
clicon_err(OE_UNIX, EINVAL, "hash is NULL");
return NULL;
@ -247,26 +247,22 @@ clicon_hash_add(clicon_hash_t *hash,
goto catch;
}
memset(new, 0, sizeof(*new));
new->h_key = strdup(key);
if (new->h_key == NULL){
clicon_err(OE_UNIX, errno, "strdup");
goto catch;
}
h = new;
}
if (vlen){
/* Make copy of value. aligned */
newval = malloc(align4(vlen+3));
newval = malloc(align4(vlen+3));
if (newval == NULL){
clicon_err(OE_UNIX, errno, "malloc");
goto catch;
}
memcpy(newval, val, vlen);
}
/* Free old value if existing variable */
if (h->h_val)
free(h->h_val);
@ -293,12 +289,11 @@ catch:
*
* @param[in] hash Hash table
* @param[in] key Variable name
*
* @retval 0 OK
* @retval -1 Key not found
*/
int
clicon_hash_del(clicon_hash_t *hash,
clicon_hash_del(clicon_hash_t *hash,
const char *key)
{
clicon_hash_t h;
@ -310,9 +305,7 @@ clicon_hash_del(clicon_hash_t *hash,
h = clicon_hash_lookup(hash, key);
if (h == NULL)
return -1;
DELQ(h, hash[hash_bucket(key)], clicon_hash_t);
free(h->h_key);
free(h->h_val);
free(h);
@ -330,7 +323,7 @@ clicon_hash_del(clicon_hash_t *hash,
* @note: vector needs to be deallocated with free
*/
int
clicon_hash_keys(clicon_hash_t *hash,
clicon_hash_keys(clicon_hash_t *hash,
char ***vector,
size_t *nkeys)
{
@ -380,7 +373,7 @@ catch:
* @retval -1 Error
*/
int
clicon_hash_dump(clicon_hash_t *hash,
clicon_hash_dump(clicon_hash_t *hash,
FILE *f)
{
int retval = -1;
@ -389,7 +382,7 @@ clicon_hash_dump(clicon_hash_t *hash,
void *val;
size_t klen;
size_t vlen;
if (hash == NULL)
goto ok;
if (clicon_hash_keys(hash, &keys, &klen) < 0)

View file

@ -40,7 +40,7 @@
/*
* Types
*/
struct clixon_instance_id_yacc {
struct clixon_instance_id_yacc {
const char *iy_name; /* Name of syntax (for error string) */
int iy_linenum; /* Number of \n in parsed buffer */
char *iy_parse_string; /* original (copy of) parse string */

View file

@ -32,7 +32,7 @@
***** END LICENSE BLOCK *****
*
* "instance-id" is a subset of XPath and defined in RF7950 Sections 9.13 and 14.
* "instance-id" is a subset of XPath and defined in RF7950 Sections 9.13 and 14.
* BNF:
* instance-identifier = ("/" (node-identifier [key-predicate+ | leaf-list-predicate | pos]))+
* key-predicate = "[" key-predicate-expr "]"
@ -80,7 +80,7 @@
#define _IY ((clixon_instance_id_yacc *)_iy)
#undef clixon_instance_id_parsewrap
int
int
clixon_instance_id_parsewrap(void)
{
return 1;
@ -99,7 +99,7 @@ uint [1-9][0-9]*
%%
<INIT,STRDQ,STRSQ>[ \t]
<INIT,STRDQ,STRSQ>[ \t]
<INIT,STRDQ,STRSQ>\n { _IY->iy_linenum++; }
<INIT,STRDQ,STRSQ>\r
<INIT,STRDQ,STRSQ><<EOF>> { return X_EOF; }
@ -112,10 +112,10 @@ uint [1-9][0-9]*
<INIT>\. { return DOT; }
<INIT>\" { _IY->iy_lex_state=INIT;BEGIN(STRDQ); return DQUOTE; }
<INIT>\' { _IY->iy_lex_state=INIT;BEGIN(STRSQ); return SQUOTE; }
<INIT>{identifier} { clixon_instance_id_parselval.string = strdup(yytext);
return IDENTIFIER; }
<INIT>{uint} { clixon_instance_id_parselval.string = strdup(yytext);
return UINT; }
<INIT>{identifier} { clixon_instance_id_parselval.string = strdup(yytext);
return IDENTIFIER; }
<INIT>{uint} { clixon_instance_id_parselval.string = strdup(yytext);
return UINT; }
<INIT>. { clixon_instance_id_parseerror(_IY, "LEXICAL ERROR\n"); return -1; }
<STRDQ>[^\"]+ { clixon_instance_id_parselval.string = strdup(yytext); return STRING; }
@ -124,7 +124,6 @@ uint [1-9][0-9]*
<STRSQ>[^\']+ { clixon_instance_id_parselval.string = strdup(yytext); return STRING; }
<STRSQ>\' { BEGIN(_IY->iy_lex_state); return SQUOTE; }
%%
/*! Initialize scanner.
@ -136,7 +135,7 @@ instance_id_scan_init(clixon_instance_id_yacc *iy)
iy->iy_lexbuf = yy_scan_string(iy->iy_parse_string);
#if 1 /* XXX: just to use unput to avoid warning */
if (0)
yyunput(0, "");
yyunput(0, "");
#endif
return 0;

View file

@ -128,7 +128,7 @@
/* Enable for debugging, steals some cycles otherwise */
#if 0
#define _PARSE_DEBUG(s) clicon_debug(1,(s))
#define _PARSE_DEBUG(s) clixon_debug(1,(s))
#else
#define _PARSE_DEBUG(s)
#endif
@ -166,7 +166,7 @@ static clixon_path *
path_append(clixon_path *list,
clixon_path *new)
{
clicon_debug(CLIXON_DBG_DETAIL, "%s()", __FUNCTION__);
clixon_debug(CLIXON_DBG_DETAIL, "%s()", __FUNCTION__);
if (new == NULL)
return NULL;
ADDQ(new, list);
@ -174,6 +174,7 @@ path_append(clixon_path *list,
}
/*! Add keyvalue to existing clixon path
*
* If cvk has one integer argument, interpret as position, eg x/y[42]
* else as keyvalue strings, eg x/y[k1="foo"][k2="bar"]
*/
@ -181,7 +182,7 @@ static clixon_path *
path_add_keyvalue(clixon_path *cp,
cvec *cvk)
{
clicon_debug(CLIXON_DBG_DETAIL, "%s()", __FUNCTION__);
clixon_debug(CLIXON_DBG_DETAIL, "%s()", __FUNCTION__);
if (cp == NULL)
goto done;
cp->cp_cvk = cvk;
@ -195,7 +196,7 @@ path_new(char *prefix,
{
clixon_path *cp = NULL;
clicon_debug(CLIXON_DBG_DETAIL, "%s(%s,%s)", __FUNCTION__, prefix, id);
clixon_debug(CLIXON_DBG_DETAIL, "%s(%s,%s)", __FUNCTION__, prefix, id);
if ((cp = malloc(sizeof(*cp))) == NULL){
clicon_err(OE_UNIX, errno, "malloc");
goto done;
@ -225,7 +226,7 @@ keyval_pos(char *uint)
char *reason=NULL;
int ret;
clicon_debug(CLIXON_DBG_DETAIL, "%s(%s)", __FUNCTION__, uint);
clixon_debug(CLIXON_DBG_DETAIL, "%s(%s)", __FUNCTION__, uint);
if ((cvv = cvec_new(1)) == NULL) {
clicon_err(OE_UNIX, errno, "cvec_new");
goto done;
@ -249,16 +250,17 @@ keyval_pos(char *uint)
}
/*! Append a key-value cv to a cvec, create the cvec if not exist
*
* @param[in] cvv Either created cvv or NULL, in whihc case it is created
* @param[in] cv Is consumed by thius function (if appended)
* @retval NULL Error
* @retval cvv Cvec
* @retval NULL Error
*/
static cvec *
keyval_add(cvec *cvv,
cg_var *cv)
{
clicon_debug(CLIXON_DBG_DETAIL, "%s()", __FUNCTION__);
clixon_debug(CLIXON_DBG_DETAIL, "%s()", __FUNCTION__);
if (cv == NULL)
goto done;
if (cvv == NULL &&
@ -284,7 +286,7 @@ keyval_set(char *name,
{
cg_var *cv = NULL;
clicon_debug(CLIXON_DBG_DETAIL, "%s(%s=%s)", __FUNCTION__, name, val);
clixon_debug(CLIXON_DBG_DETAIL, "%s(%s=%s)", __FUNCTION__, name, val);
if ((cv = cv_new(CGV_STRING)) == NULL){
clicon_err(OE_UNIX, errno, "cv_new");
goto done;

View file

@ -191,8 +191,8 @@ arraytype2str(enum array_element_type lt)
* @retval arraytype Type of array
*/
static enum array_element_type
array_eval(cxobj *xprev,
cxobj *x,
array_eval(cxobj *xprev,
cxobj *x,
cxobj *xnext)
{
enum array_element_type arraytype = NO_ARRAY;
@ -207,7 +207,7 @@ array_eval(cxobj *xprev,
arraytype = BODY_ARRAY;
goto done;
}
if (xnext &&
if (xnext &&
xml_type(xnext)==CX_ELMNT &&
strcmp(xml_name(x), xml_name(xnext))==0){
ns2 = xml_find_type_value(xnext, NULL, "xmlns", CX_ATTR);
@ -245,15 +245,16 @@ array_eval(cxobj *xprev,
*
* @param[out] cb cbuf (encoded)
* @param[in] str string (unencoded)
* @retval 0 OK
*/
static int
json_str_escape_cdata(cbuf *cb,
char *str)
{
int retval = -1;
int i;
int retval = -1;
size_t len;
int i;
len = strlen(str);
for (i=0; i<len; i++)
switch (str[i]){
@ -315,8 +316,8 @@ json2xml_decode_identityref(cxobj *x,
cvec *nsc = NULL;
char *prefix2 = NULL;
cbuf *cbv = NULL;
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
yspec = ys_spec(y);
if ((xb = xml_body_get(x)) == NULL)
goto ok;
@ -334,7 +335,7 @@ json2xml_decode_identityref(cxobj *x,
*/
if (xml_nsctx_node(x, &nsc) < 0)
goto done;
clicon_debug(1, "%s prefix:%s body:%s namespace:%s",
clixon_debug(CLIXON_DBG_DEFAULT, "%s prefix:%s body:%s namespace:%s",
__FUNCTION__, prefix, body, ns);
if (!xml_nsctx_get_prefix(nsc, ns, &prefix2)){
/* (no) insert a xmlns:<prefix> statement
@ -368,7 +369,7 @@ json2xml_decode_identityref(cxobj *x,
else{
if (xerr && netconf_unknown_namespace_xml(xerr, "application",
prefix,
"No module corresponding to prefix") < 0)
"No module corresponding to prefix") < 0)
goto done;
goto fail;
}
@ -449,10 +450,12 @@ json2xml_decode(cxobj *x,
/*! Encode leaf/leaf_list identityref type from XML to JSON
*
* @param[in] x XML body node
* @param[in] body body string
* @param[in] ys Yang spec of parent
* @param[out] cb Encoded string
* @param[in] x XML body node
* @param[in] body body string
* @param[in] ys Yang spec of parent
* @param[out] cb Encoded string
* @retval 0 OK
* @retval -1 Error
*/
static int
xml2json_encode_identityref(cxobj *xb,
@ -468,7 +471,7 @@ xml2json_encode_identityref(cxobj *xb,
yang_stmt *yspec;
yang_stmt *my_ymod;
clicon_debug(1, "%s %s", __FUNCTION__, body);
clixon_debug(CLIXON_DBG_DEFAULT, "%s %s", __FUNCTION__, body);
my_ymod = ys_module(yp);
yspec = ys_spec(yp);
if (nodeid_split(body, &prefix, &id) < 0)
@ -477,7 +480,7 @@ xml2json_encode_identityref(cxobj *xb,
if (xml2ns(xb, prefix, &namespace) < 0)
goto done;
/* We got the namespace, now get the module */
// clicon_debug(1, "%s body:%s prefix:%s namespace:%s", __FUNCTION__, body, prefix, namespace);
// clixon_debug(CLIXON_DBG_DEFAULT, "%s body:%s prefix:%s namespace:%s", __FUNCTION__, body, prefix, namespace);
#ifdef IDENTITYREF_KLUDGE
if (namespace == NULL){
/* If we dont find namespace here, we assume it is because of a missing
@ -493,7 +496,6 @@ xml2json_encode_identityref(cxobj *xb,
#endif
{
if ((ymod = yang_find_module_by_namespace(yspec, namespace)) != NULL){
if (ymod == my_ymod)
cprintf(cb, "%s", id);
else{
@ -514,10 +516,12 @@ xml2json_encode_identityref(cxobj *xb,
/*! Encode leaf/leaf_list types from XML to JSON
*
* @param[in] xb XML body
* @param[in] xp XML parent
* @param[in] yp Yang spec of parent
* @param[out] cb0 Encoded string
* @param[in] xb XML body
* @param[in] xp XML parent
* @param[in] yp Yang spec of parent
* @param[out] cb0 Encoded string
* @retval 0 OK
* @retval -1 Error
*/
static int
xml2json_encode_leafs(cxobj *xb,
@ -541,7 +545,7 @@ xml2json_encode_leafs(cxobj *xb,
}
body = xb?xml_value(xb):NULL;
if (yp == NULL){
cprintf(cb, "%s", body?body:"null");
cprintf(cb, "%s", body?body:"null");
goto ok; /* unknown */
}
keyword = yang_keyword_get(yp);
@ -552,7 +556,7 @@ xml2json_encode_leafs(cxobj *xb,
goto done;
restype = ytype?yang_argument_get(ytype):NULL;
cvtype = yang_type2cv(yp);
switch (cvtype){
switch (cvtype){
case CGV_STRING:
case CGV_REST:
if (body==NULL)
@ -738,6 +742,8 @@ json_metadata_encoding(cbuf *cb,
* @param[in] pretty Pretty-print output (2 means debug)
* @param[in] modname Name of yang module
* @param[in,out] metacb Encode into cbuf
* @retval 0 OK
* @retval -1 Error
* @see RFC7952
*/
static int
@ -754,7 +760,7 @@ xml2json_encode_attr(cxobj *xa,
char *namespace = NULL;
yang_stmt *ymod;
enum rfc_6020 ykeyw;
if (xml2ns(xa, xml_prefix(xa), &namespace) < 0)
goto done;
/* Check for (1) registered meta-data */
@ -792,14 +798,16 @@ xml2json_encode_attr(cxobj *xa,
/*! Do the actual work of translating XML to JSON
*
* @param[out] cb Cligen text buffer containing json on exit
* @param[in] x XML tree structure containing XML to translate
* @param[in] arraytype Does x occur in a array (of its parent) and how?
* @param[in] level Indentation level
* @param[in] pretty Pretty-print output (2 means debug)
* @param[in] flat Dont print NO_ARRAY object name (for _vec call)
* @param[in] modname0
* @param[out] metacbp Meta encoding of attribute
* @param[out] cb Cligen text buffer containing json on exit
* @param[in] x XML tree structure containing XML to translate
* @param[in] arraytype Does x occur in a array (of its parent) and how?
* @param[in] level Indentation level
* @param[in] pretty Pretty-print output (2 means debug)
* @param[in] flat Dont print NO_ARRAY object name (for _vec call)
* @param[in] modname0
* @param[out] metacbp Meta encoding of attribute
* @retval 0 OK
* @retval -1 Error
*
* @note Does not work with XML attributes
* The following matrix explains how the mapping is done.
@ -829,7 +837,7 @@ xml2json_encode_attr(cxobj *xa,
| |\n\t] |\n\t] |\n\t}\t] |
+----------+--------------+--------------+--------------+
*/
static int
static int
xml2json1_cbuf(cbuf *cb,
cxobj *x,
enum array_element_type arraytype,
@ -868,7 +876,7 @@ xml2json1_cbuf(cbuf *cb,
}
childt = child_type(x);
if (pretty==2)
cprintf(cb, "#%s_array, %s_child ",
cprintf(cb, "#%s_array, %s_child ",
arraytype2str(arraytype),
childtype2str(childt));
switch(arraytype){
@ -880,7 +888,7 @@ xml2json1_cbuf(cbuf *cb,
case NO_ARRAY:
if (!flat){
cprintf(cb, "%*s\"", pretty?(level*PRETTYPRINT_INDENT):0, "");
if (modname)
if (modname)
cprintf(cb, "%s:", modname);
cprintf(cb, "%s\":%s", xml_name(x), pretty?" ":"");
}
@ -905,7 +913,7 @@ xml2json1_cbuf(cbuf *cb,
cprintf(cb, "%s:", modname);
cprintf(cb, "%s\":%s", xml_name(x), pretty?" ":"");
level++;
cprintf(cb, "[%s%*s",
cprintf(cb, "[%s%*s",
pretty?"\n":"",
pretty?(level*PRETTYPRINT_INDENT):0, "");
switch (childt){
@ -925,7 +933,7 @@ xml2json1_cbuf(cbuf *cb,
case MIDDLE_ARRAY:
case LAST_ARRAY:
level++;
cprintf(cb, "%*s",
cprintf(cb, "%*s",
pretty?(level*PRETTYPRINT_INDENT):0, "");
switch (childt){
case NULL_CHILD:
@ -961,11 +969,11 @@ xml2json1_cbuf(cbuf *cb,
goto done;
continue;
}
xc_arraytype = array_eval(i?xml_child_i(x,i-1):NULL,
xc,
xc_arraytype = array_eval(i?xml_child_i(x,i-1):NULL,
xc,
xml_child_i(x, i+1));
if (xml2json1_cbuf(cb,
xc,
if (xml2json1_cbuf(cb,
xc,
xc_arraytype,
level+1, pretty, 0, modname0,
metacbc) < 0)
@ -988,7 +996,7 @@ xml2json1_cbuf(cbuf *cb,
case BODY_CHILD:
break;
case ANY_CHILD:
cprintf(cb, "%s%*s}",
cprintf(cb, "%s%*s}",
pretty?"\n":"",
pretty?(level*PRETTYPRINT_INDENT):0, "");
break;
@ -1004,7 +1012,7 @@ xml2json1_cbuf(cbuf *cb,
case BODY_CHILD:
break;
case ANY_CHILD:
cprintf(cb, "%s%*s}",
cprintf(cb, "%s%*s}",
pretty?"\n":"",
pretty?(level*PRETTYPRINT_INDENT):0, "");
level--;
@ -1021,7 +1029,7 @@ xml2json1_cbuf(cbuf *cb,
cprintf(cb, "%s",pretty?"\n":"");
break;
case ANY_CHILD:
cprintf(cb, "%s%*s}",
cprintf(cb, "%s%*s}",
pretty?"\n":"",
pretty?(level*PRETTYPRINT_INDENT):0, "");
cprintf(cb, "%s",pretty?"\n":"");
@ -1058,9 +1066,9 @@ xml2json1_cbuf(cbuf *cb,
* @see clixon_xml2cbuf XML corresponding function
* @see xml2json_cbuf_vec Top symbol is list
*/
static int
xml2json_cbuf1(cbuf *cb,
cxobj *x,
static int
xml2json_cbuf1(cbuf *cb,
cxobj *x,
int pretty,
int autocliext)
{
@ -1069,7 +1077,7 @@ xml2json_cbuf1(cbuf *cb,
yang_stmt *y;
enum array_element_type arraytype = NO_ARRAY;
int exist = 0;
y = xml_spec(x);
if (autocliext && y != NULL) {
if (yang_extension_value(y, "hide-show", CLIXON_AUTOCLI_NS, &exist, NULL) < 0)
@ -1077,10 +1085,9 @@ xml2json_cbuf1(cbuf *cb,
if (exist)
goto ok;
}
cprintf(cb, "%*s{%s",
pretty?level*PRETTYPRINT_INDENT:0,"",
cprintf(cb, "%*s{%s",
pretty?level*PRETTYPRINT_INDENT:0,"",
pretty?"\n":"");
if (y != NULL){
switch (yang_keyword_get(y)){
case Y_LEAF_LIST:
@ -1092,8 +1099,8 @@ xml2json_cbuf1(cbuf *cb,
break;
}
}
if (xml2json1_cbuf(cb,
x,
if (xml2json1_cbuf(cb,
x,
arraytype,
level+1,
pretty,
@ -1101,7 +1108,7 @@ xml2json_cbuf1(cbuf *cb,
NULL, /* ancestor modname / namespace */
NULL) < 0)
goto done;
cprintf(cb, "%s%*s}%s",
cprintf(cb, "%s%*s}%s",
pretty?"\n":"",
pretty?level*PRETTYPRINT_INDENT:0,"",
pretty?"\n":"");
@ -1131,9 +1138,9 @@ xml2json_cbuf1(cbuf *cb,
* @endcode
* @see xml2json_cbuf where the top level object is included
*/
int
clixon_json2cbuf(cbuf *cb,
cxobj *xt,
int
clixon_json2cbuf(cbuf *cb,
cxobj *xt,
int pretty,
int skiptop,
int autocliext)
@ -1175,8 +1182,8 @@ clixon_json2cbuf(cbuf *cb,
* Example: <b/><c/> --> <a><b/><c/></a> --> {"b" : null,"c" : null}
* @see clixon_json2cbuf
*/
int
xml2json_cbuf_vec(cbuf *cb,
int
xml2json_cbuf_vec(cbuf *cb,
cxobj **vec,
size_t veclen,
int pretty,
@ -1188,7 +1195,7 @@ xml2json_cbuf_vec(cbuf *cb,
int i;
cxobj *xc0;
cxobj *xc;
cvec *nsc = NULL;
cvec *nsc = NULL;
if ((xp = xml_new("xml2json", NULL, CX_ELMNT)) == NULL)
goto done;
@ -1220,8 +1227,8 @@ xml2json_cbuf_vec(cbuf *cb,
cprintf(cb, "[%s", pretty?"\n":" ");
level++;
}
if (xml2json1_cbuf(cb,
xp,
if (xml2json1_cbuf(cb,
xp,
NO_ARRAY,
level,
pretty,
@ -1230,7 +1237,7 @@ xml2json_cbuf_vec(cbuf *cb,
if (0){
level--;
cprintf(cb, "%s]%s",
cprintf(cb, "%s]%s",
pretty?"\n":"",
pretty?"\n":""); /* top object */
}
@ -1261,8 +1268,8 @@ xml2json_cbuf_vec(cbuf *cb,
* goto err;
* @endcode
*/
int
clixon_json2file(FILE *f,
int
clixon_json2file(FILE *f,
cxobj *xn,
int pretty,
clicon_output_cb *fn,
@ -1294,7 +1301,7 @@ clixon_json2file(FILE *f,
* @param[in] xn clicon xml tree
*/
int
json_print(FILE *f,
json_print(FILE *f,
cxobj *x)
{
return clixon_json2file(f, x, 1, fprintf, 0, 0);
@ -1316,8 +1323,8 @@ json_print(FILE *f,
* Example: <b/><c/> --> <a><b/><c/></a> --> {"b" : null,"c" : null}
* @see xml2json1_cbuf
*/
int
xml2json_vec(FILE *f,
int
xml2json_vec(FILE *f,
cxobj **vec,
size_t veclen,
int pretty,
@ -1367,9 +1374,9 @@ json_xmlns_translate(yang_stmt *yspec,
char *modname = NULL;
cxobj *xc;
int ret;
if ((modname = xml_prefix(x)) != NULL){ /* prefix is here module name */
/* Special case for ietf-netconf -> ietf-restconf translation
/* Special case for ietf-netconf -> ietf-restconf translation
* A special case is for return data on the form {"data":...}
* See also xml2json1_cbuf
*/
@ -1419,16 +1426,16 @@ json_xmlns_translate(yang_stmt *yspec,
* @param[in] yspec Yang specification (if rfc 7951)
* @param[out] xt XML top of tree typically w/o children on entry (but created)
* @param[out] xerr Reason for invalid returned as netconf err msg
* @retval 1 OK and valid
* @retval 0 Invalid (only if yang spec)
* @retval -1 Error with clicon_err called
*
* @see _xml_parse for XML variant
* @retval 1 OK and valid
* @retval 0 Invalid (only if yang spec)
* @retval -1 Error with clicon_err called
* @see http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf
* @see RFC 7951
*/
static int
_json_parse(char *str,
static int
_json_parse(char *str,
int rfc7951,
yang_bind yb,
yang_stmt *yspec,
@ -1442,8 +1449,8 @@ _json_parse(char *str,
cbuf *cberr = NULL;
int i;
int failed = 0; /* yang assignment */
clicon_debug(1, "%s %d %s", __FUNCTION__, yb, str);
clixon_debug(CLIXON_DBG_DEFAULT, "%s %d %s", __FUNCTION__, yb, str);
jy.jy_parse_string = str;
jy.jy_linenum = 1;
jy.jy_current = xt;
@ -1506,7 +1513,7 @@ _json_parse(char *str,
break;
case YB_NONE:
break;
case YB_RPC:
case YB_RPC:
if ((ret = xml_bind_yang_rpc(NULL, x, yspec, xerr)) < 0)
goto done;
if (ret == 0)
@ -1529,14 +1536,14 @@ _json_parse(char *str,
goto done;
retval = 1;
done:
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
clixon_debug(CLIXON_DBG_DEFAULT, "%s retval:%d", __FUNCTION__, retval);
if (cberr)
cbuf_free(cberr);
json_parse_exit(&jy);
json_scan_exit(&jy);
if (jy.jy_xvec)
free(jy.jy_xvec);
return retval;
return retval;
fail: /* invalid */
retval = 0;
goto done;
@ -1564,15 +1571,15 @@ _json_parse(char *str,
* @see clixon_xml_parse_string XML instead of JSON
* @see clixon_json_parse_file From a file
*/
int
clixon_json_parse_string(char *str,
int
clixon_json_parse_string(char *str,
int rfc7951,
yang_bind yb,
yang_stmt *yspec,
cxobj **xt,
cxobj **xerr)
{
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
if (xt==NULL){
clicon_err(OE_JSON, EINVAL, "xt is NULL");
return -1;
@ -1602,6 +1609,9 @@ clixon_json_parse_string(char *str,
* @param[in] yspec Yang specification, or NULL
* @param[in,out] xt Pointer to (XML) parse tree. If empty, create.
* @param[out] xerr Reason for invalid returned as netconf err msg
* @retval 1 OK and valid
* @retval 0 Invalid (only if yang spec) w xerr set
* @retval -1 Error with clicon_err called
*
* @code
* cxobj *xt = NULL;
@ -1612,11 +1622,6 @@ clixon_json_parse_string(char *str,
* @note you need to free the xml parse tree after use, using xml_free()
* @note, If xt empty, a top-level symbol will be added so that <tree../> will be: <top><tree.../></tree></top>
* @note May block on file I/O
*
* @retval 1 OK and valid
* @retval 0 Invalid (only if yang spec) w xerr set
* @retval -1 Error with clicon_err called
*
* @see clixon_json_parse_string
* @see RFC7951
*/
@ -1685,7 +1690,7 @@ clixon_json_parse_file(FILE *fp,
}
if (jsonbuf)
free(jsonbuf);
return retval;
return retval;
fail:
retval = 0;
goto done;

View file

@ -40,7 +40,7 @@
* Types
*/
struct clixon_json_yacc {
struct clixon_json_yacc {
int jy_linenum; /* Number of \n in parsed buffer */
char *jy_parse_string; /* original (copy of) parse string */
void *jy_lexbuf; /* internal parse buffer from lex */

View file

@ -70,7 +70,7 @@
#define _JY ((clixon_json_yacc *)_yy)
#undef clixon_json_parsewrap
int
int
clixon_json_parsewrap(void)
{
return 1;
@ -91,9 +91,9 @@ hex [A-Fa-f0-9]
%%
<START>[ \t]
<START>[ \t]
<START>\n { _JY->jy_linenum++; }
<START>\r
<START>\r
<START><<EOF>> { return J_EOF; }
<START>\{ { return *yytext; }
<START>\} { return *yytext; }
@ -123,13 +123,13 @@ hex [A-Fa-f0-9]
<ESCAPE>u { BEGIN(HEXDIG); }
<ESCAPE>\n { return -1; }
<ESCAPE>. { return -1; }
<HEXDIG>{hex}{hex}{hex}{hex} {
<HEXDIG>{hex}{hex}{hex}{hex} {
char buf[5] = {0, };
BEGIN(STRING);
BEGIN(STRING);
if (clixon_unicode2utf8(yytext, buf, 5) < 0)
return -1;
strncpy(yytext, buf, 5);
clixon_json_parselval.string = yytext;
clixon_json_parselval.string = yytext;
return J_STRING;
}
<HEXDIG>\n { return -1;}
@ -147,7 +147,7 @@ json_scan_init(clixon_json_yacc *jy)
jy->jy_lexbuf = yy_scan_string (jy->jy_parse_string);
#if 1 /* XXX: just to use unput to avoid warning */
if (0)
yyunput(0, "");
yyunput(0, "");
#endif
return 0;

View file

@ -107,7 +107,7 @@ object.
#define _YYERROR(msg) {clicon_err(OE_JSON, 0, "YYERROR %s '%s' %d", (msg), clixon_json_parsetext, _JY->jy_linenum); YYERROR;}
/* add _yy to error parameters */
#define YY_(msgid) msgid
#define YY_(msgid) msgid
#include "clixon_config.h"
@ -137,7 +137,7 @@ object.
/* Enable for debugging, steals some cycles otherwise */
#if 0
#define _PARSE_DEBUG(s) clicon_debug(1,(s))
#define _PARSE_DEBUG(s) clixon_debug(1,(s))
#else
#define _PARSE_DEBUG(s)
#endif
@ -148,14 +148,14 @@ extern int clixon_json_parseget_lineno (void);
also called from yacc generated code *
*/
void
void
clixon_json_parseerror(void *_jy,
char *s)
char *s)
{
clicon_err(OE_JSON, 0, "json_parse: line %d: %s at or before: '%s'",
_JY->jy_linenum ,
s,
clixon_json_parsetext);
clicon_err(OE_JSON, 0, "json_parse: line %d: %s at or before: '%s'",
_JY->jy_linenum,
s,
clixon_json_parsetext);
if (_JY->jy_cbuf_str)
cbuf_free(_JY->jy_cbuf_str);
return;
@ -164,7 +164,7 @@ clixon_json_parseerror(void *_jy,
int
json_parse_init(clixon_json_yacc *jy)
{
// clicon_debug_init(2, NULL);
// clixon_debug_init(2, NULL);
return 0;
}
@ -173,8 +173,9 @@ json_parse_exit(clixon_json_yacc *jy)
{
return 0;
}
/*! Create xml object from json object name (eg "string")
*
* Split name into prefix:name (extended JSON RFC7951)
*/
static int
@ -186,7 +187,7 @@ json_current_new(clixon_json_yacc *jy,
char *prefix = NULL;
char *id = NULL;
clicon_debug(CLIXON_DBG_DETAIL, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DETAIL, "%s", __FUNCTION__);
/* Find colon separator and if found split into prefix:name */
if (nodeid_split(name, &prefix, &id) < 0)
goto done;
@ -213,8 +214,8 @@ json_current_new(clixon_json_yacc *jy,
static int
json_current_pop(clixon_json_yacc *jy)
{
clicon_debug(CLIXON_DBG_DETAIL, "%s", __FUNCTION__);
if (jy->jy_current)
clixon_debug(CLIXON_DBG_DETAIL, "%s", __FUNCTION__);
if (jy->jy_current)
jy->jy_current = xml_parent(jy->jy_current);
return 0;
}
@ -224,7 +225,7 @@ json_current_clone(clixon_json_yacc *jy)
{
cxobj *xn;
clicon_debug(CLIXON_DBG_DETAIL, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DETAIL, "%s", __FUNCTION__);
if (jy->jy_current == NULL){
return -1;
}
@ -243,7 +244,6 @@ json_current_clone(clixon_json_yacc *jy)
maybe_prefixed_name = strdup(name);
}
json_current_new(jy, maybe_prefixed_name);
if (maybe_prefixed_name)
free(maybe_prefixed_name);
}
@ -251,31 +251,31 @@ json_current_clone(clixon_json_yacc *jy)
}
static int
json_current_body(clixon_json_yacc *jy,
json_current_body(clixon_json_yacc *jy,
char *value)
{
int retval = -1;
cxobj *xn;
clicon_debug(CLIXON_DBG_DETAIL, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DETAIL, "%s", __FUNCTION__);
if ((xn = xml_new("body", jy->jy_current, CX_BODY)) == NULL)
goto done;
goto done;
if (value && xml_value_append(xn, value) < 0)
goto done;
goto done;
retval = 0;
done:
return retval;
}
%}
%}
%%
/*
*/
/* top: json -> value is also possible */
json : value J_EOF { _PARSE_DEBUG("json->value"); YYACCEPT; }
json : value J_EOF { _PARSE_DEBUG("json->value"); YYACCEPT; }
;
value : J_TRUE { json_current_body(_JY, "true"); _PARSE_DEBUG("value->TRUE");}
@ -296,7 +296,7 @@ objlist : pair { _PARSE_DEBUG("objlist->pair");}
| objlist ',' pair { _PARSE_DEBUG("objlist->objlist , pair");}
;
pair : string { json_current_new(_JY, cbuf_get($1));cbuf_free($1); _JY->jy_cbuf_str = NULL;} ':'
pair : string { json_current_new(_JY, cbuf_get($1));cbuf_free($1); _JY->jy_cbuf_str = NULL;} ':'
value { json_current_pop(_JY);}{ _PARSE_DEBUG("pair->string : value");}
;
@ -325,7 +325,7 @@ ustring : ustring J_STRING
_JY->jy_cbuf_str = cb;
cbuf_append_str(cb,$1);
$$=cb;
}
}
;
number : J_NUMBER { $$ = $1; }

View file

@ -80,7 +80,7 @@ static int _clixon_log_trunc = 0;
*
* Make syslog(3) calls with specified ident and gates calls of level upto specified level (upto).
* May also print to stderr, if err is set.
* Applies to clicon_err() and clicon_debug too
* Applies to clicon_err() and clixon_debug too
*
* @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)).
@ -92,15 +92,15 @@ static int _clixon_log_trunc = 0;
* @endcode
*/
int
clicon_log_init(char *ident,
int upto,
int flags)
clicon_log_init(char *ident,
int upto,
int flags)
{
_logflags = flags;
if (flags & CLICON_LOG_SYSLOG){
if (setlogmask(LOG_UPTO(upto)) < 0)
/* Cant syslog here */
fprintf(stderr, "%s: setlogmask: %s\n", __FUNCTION__, strerror(errno));
fprintf(stderr, "%s: setlogmask: %s\n", __FUNCTION__, strerror(errno));
openlog(ident, LOG_PID, LOG_USER); /* LOG_PUSER is achieved by direct stderr logs in clicon_log */
}
return 0;
@ -116,9 +116,10 @@ clicon_log_exit(void)
}
/*! Utility function to set log destination/flag using command-line option
*
* @param[in] c Log option,one of s,f,e,o
* @retval -1 No match
* @retval 0 One of CLICON_LOG_SYSLOG|STDERR|STDOUT|FILE
* @retval -1 No match
*/
int
clicon_log_opt(char c)
@ -143,15 +144,16 @@ clicon_log_opt(char c)
break;
default:
break;
}
}
return logdst;
}
/*! If log flags include CLICON_LOG_FILE, set the file
*
* @param[in] filename File to log to
* @retval 0 OK
* @retval -1 Error
* @see clicon_debug_init where a strean
* @see clixon_debug_init where a strean
*/
int
clicon_log_file(char *filename)
@ -198,7 +200,7 @@ flogtime(FILE *f)
gettimeofday(&tv, NULL);
localtime_r((time_t*)&tv.tv_sec, &tm);
fprintf(f, "%s %2d %02d:%02d:%02d: ",
fprintf(f, "%s %2d %02d:%02d:%02d: ",
mon2name(tm.tm_mon), tm.tm_mday,
tm.tm_hour, tm.tm_min, tm.tm_sec);
return 0;
@ -223,7 +225,7 @@ slogtime(void)
}
gettimeofday(&tv, NULL);
tm = localtime((time_t*)&tv.tv_sec);
snprintf(str, 18, "%s %2d %02d:%02d:%02d: ",
snprintf(str, 18, "%s %2d %02d:%02d:%02d: ",
mon2name(tm->tm_mon), tm->tm_mday,
tm->tm_hour, tm->tm_min, tm->tm_sec);
return str;
@ -236,11 +238,11 @@ slogtime(void)
* @param[in] msg Message to print as argv.
* This is the _only_ place the actual syslog (or stderr) logging is made in clicon,..
* @note syslog makes its own filtering, but if log to stderr we do it here
* @see clicon_debug
* @see clixon_debug
*/
int
clicon_log_str(int level,
char *msg)
clicon_log_str(int level,
char *msg)
{
if (_logflags & CLICON_LOG_SYSLOG)
syslog(LOG_MAKEPRI(LOG_USER, level), "%s", msg); // XXX this may block
@ -262,7 +264,7 @@ clicon_log_str(int level,
fprintf(_logfile, "%s\n", msg);
fflush(_logfile);
}
/* Enable this if you want syslog in a stream. But there are problems with
/* Enable this if you want syslog in a stream. But there are problems with
* recursion
*/
done:
@ -271,9 +273,11 @@ clicon_log_str(int level,
/*! Make a logging call to syslog using variable arg syntax.
*
* @param[in] level log level, eg LOG_DEBUG,LOG_INFO,...,LOG_EMERG. This
* is OR:d with facility == LOG_USER
* @param[in] format Message to print as argv.
* @param[in] level log level, eg LOG_DEBUG,LOG_INFO,...,LOG_EMERG. This
* is OR:d with facility == LOG_USER
* @param[in] format Message to print as argv.
* @retval 0 OK
* @retval -1 Error
* @code
clicon_log(LOG_NOTICE, "%s: dump to dtd not supported", __PROGRAM__);
* @endcode
@ -281,13 +285,13 @@ clicon_log_str(int level,
* @see clicon_log_xml
*/
int
clicon_log(int level,
clicon_log(int level,
const char *format, ...)
{
int retval = -1;
va_list args;
size_t len;
char *msg = NULL;
int retval = -1;
size_t trunc;
/* first round: compute length of debug message */
@ -325,9 +329,9 @@ clicon_log(int level,
/*! Initialize debug messages. Set debug level.
*
* Initialize debug module. The level is used together with clicon_debug(dbglevel) calls as follows:
* Initialize debug module. The level is used together with clixon_debug(dbglevel) calls as follows:
* print message if level >= dbglevel.
* Example: clicon_debug_init(1) -> debug(1) is printed, but not debug(2).
* Example: clixon_debug_init(1) -> debug(1) is printed, but not debug(2).
* Normally, debug messages are sent to clicon_log() which in turn can be sent to syslog and/or stderr.
* But you can also override this with a specific debug file so that debug messages are written on the file
* independently of log or errors. This is to ensure that a syslog of normal logs is unpolluted by extensive
@ -341,11 +345,11 @@ clicon_log(int level,
* @see clicon_log_file where a filename can be given
*/
int
clicon_debug_init(int dbglevel,
clixon_debug_init(int dbglevel,
FILE *f)
{
_clixon_debug = dbglevel; /* Global variable */
if (f != NULL){
if (_logfile)
fclose(_logfile);
@ -355,7 +359,7 @@ clicon_debug_init(int dbglevel,
}
int
clicon_debug_get(void)
clixon_debug_get(void)
{
return _clixon_debug;
}
@ -363,27 +367,29 @@ clicon_debug_get(void)
/*! Print a debug message with debug-level. Settings determine where msg appears.
*
* If the dbglevel passed in the function is equal to or lower than the one set by
* clicon_debug_init(level). That is, only print debug messages <= than what you want:
* clixon_debug_init(level). That is, only print debug messages <= than what you want:
* print message if level >= dbglevel.
* The message is sent to clicon_log. EIther to syslog, stderr or both, depending on
* clicon_log_init() setting
* @param[in] dbglevel Mask of CLIXON_DBG_DEFAULT and other masks
* @param[in] format Message to print as argv.
* @see clicon_debug_xml Specialization for XML tree
* @param[in] dbglevel Mask of CLIXON_DBG_DEFAULT and other masks
* @param[in] format Message to print as argv.
* @retval 0 OK
* @retval -1 Error
* @see clixon_debug_xml Specialization for XML tree
* @see CLIXON_DBG_DEFAULT and other flags
*/
int
clicon_debug(int dbglevel,
clixon_debug(int dbglevel,
const char *format, ...)
{
int retval = -1;
va_list args;
size_t len;
char *msg = NULL;
int retval = -1;
size_t trunc;
/* Mask debug level with global dbg variable */
if ((dbglevel & clicon_debug_get()) == 0)
if ((dbglevel & clixon_debug_get()) == 0)
return 0;
/* first round: compute length of debug message */
va_start(args, format);
@ -393,7 +399,6 @@ clicon_debug(int dbglevel,
/* Truncate long debug strings */
if ((trunc = clicon_log_string_limit_get()) && trunc < len)
len = trunc;
/* allocate a message string exactly fitting the message length */
if ((msg = malloc(len+1)) == NULL){
clicon_err(OE_UNIX, errno, "malloc");
@ -416,6 +421,7 @@ clicon_debug(int dbglevel,
}
/*! Translate month number (0..11) to a three letter month name
*
* @param[in] md month number, where 0 is january
*/
char *

View file

@ -79,13 +79,14 @@
#define NACM_NS "urn:ietf:params:xml:ns:yang:ietf-netconf-acm"
/*! Match nacm access operations according to RFC8341 3.4.4.
*
* Incoming RPC Message Validation Step 7 (c)
* The rule's "access-operations" leaf has the "exec" bit set or
* has the special value "*".
* @param[in] mode Primary mode, eg read, create, update, delete, exec
* @param[in] mode2 Secondary mode, eg "write"
* @retval 0 No match
* @retval 1 Match
* @retval 1 Match
* @retval 0 No match
* @note access_operations is bit-fields
*/
static int
@ -105,14 +106,15 @@ match_access(char *access_operations,
}
/*! Match nacm single rule. Either match with access or deny. Or not match.
*
* @param[in] rpc rpc name
* @param[in] module Yang module name
* @param[in] xrule NACM rule XML tree
* @param[out] cbret Cligen buffer result. Set to an error msg if retval=0.
* @retval -1 Error
* @retval 0 Matching rule AND Not access and cbret set
* @retval 1 Matching rule AND Access
* @retval 2 No matching rule Goto step 10
* @retval 2 No matching rule Goto step 10
* @retval 1 Matching rule AND Access
* @retval 0 Matching rule AND Not access and cbret set
* @retval -1 Error
* @see RFC8341 3.4.4. Incoming RPC Message Validation
7.(cont) A rule matches if all of the following criteria are met:
* The rule's "module-name" leaf is "*" or equals the name of
@ -135,7 +137,7 @@ nacm_rule_rpc(char *rpc,
char *module_rule; /* rule module name */
char *rpc_rule;
char *access_operations;
/* 7a) The rule's "module-name" leaf is "*" or equals the name of
the YANG module where the protocol operation is defined. */
if ((module_rule = xml_find_body(xrule, "module-name")) == NULL)
@ -166,14 +168,15 @@ nacm_rule_rpc(char *rpc,
}
/*! Process nacm incoming RPC message validation steps
*
* @param[in] module Yang module name
* @param[in] rpc rpc name
* @param[in] username User name of requestor
* @param[in] xnacm NACM xml tree
* @param[out] cbret Cligen buffer result. Set to an error msg if retval=0.
* @retval -1 Error
* @retval 0 Not access and cbret set
* @retval 1 Access
* @param[out] cbret Cligen buffer result. Set to an error msg if retval=0.
* @retval 1 Access
* @retval 0 Not access and cbret set
* @retval -1 Error
* @see RFC8341 3.4.4. Incoming RPC Message Validation
* @see nacm_datanode_write
* @see nacm_datanode_read
@ -200,7 +203,7 @@ nacm_rpc(char *rpc,
char *action;
int match= 0;
cvec *nsc = NULL;
/* Create namespace context for with nacm namespace as default */
if ((nsc = xml_nsctx_init(NULL, NACM_NS)) == NULL)
goto done;
@ -241,7 +244,7 @@ nacm_rpc(char *rpc,
continue;
/* 7. For each rule-list entry found, process all rules, in order,
until a rule that matches the requested access operation is
found.
found.
*/
if (xpath_vec(rlist, nsc, "rule", &rvec, &rlen) < 0)
goto done;
@ -295,7 +298,7 @@ nacm_rpc(char *rpc,
permit:
retval = 1;
done:
clicon_debug(1, "%s retval:%d (0:deny 1:permit)", __FUNCTION__, retval);
clixon_debug(CLIXON_DBG_DEFAULT, "%s retval:%d (0:deny 1:permit)", __FUNCTION__, retval);
if (nsc)
xml_nsctx_free(nsc);
if (gvec)
@ -354,11 +357,15 @@ prepvec_add(prepvec **pv_listp,
}
/*! Prepare datastructures before running through XML tree
*
* Save rules in a "cache"
* These rules match:
* - user/group
* - have read access-op, etc
* Also make instance-id lookups on top object for each rule. Assume at most one result
* @param[in] h Clixon handle
* @retval 0 OK
* @retval -1 Error
*/
static int
nacm_datanode_prepare(clicon_handle h,
@ -378,7 +385,7 @@ nacm_datanode_prepare(clicon_handle h,
int k;
char *gname;
cxobj **rvec = NULL; /* rules */
size_t rlen;
size_t rlen;
cxobj *xrule;
cxobj *pathobj;
char *access_operations;
@ -414,14 +421,14 @@ nacm_datanode_prepare(clicon_handle h,
leaf has the "read" bit set or has the special value "*" */
access_operations = xml_find_body(xrule, "access-operations");
switch (access){
case NACM_READ:
case NACM_READ:
/* 6c) For a "read" access operation, the rule's "access-operations"
leaf has the "read" bit set or has the special value "*" */
if (!match_access(access_operations, "read", NULL))
continue;
break;
case NACM_CREATE:
/* 6d) For a "create" access operation, the rule's "access-operations"
/* 6d) For a "create" access operation, the rule's "access-operations"
leaf has the "create" bit set or has the special value "*". */
if (!match_access(access_operations, "create", "write"))
continue;
@ -499,7 +506,7 @@ nacm_datanode_prepare(clicon_handle h,
if (rvec){
free(rvec);
rvec=NULL;
}
}
}
retval = 0;
done:
@ -517,14 +524,15 @@ nacm_datanode_prepare(clicon_handle h,
*/
/*! Match specific rule to specific requested node
*
* @param[in] xn XML node (requested node)
* @param[in] xrule NACM rule
* @param[in] xp Xpath match
* @param[in] yspec YANG spec
* @retval -1 Error
* @retval 0 OK and rule does not match
* @retval 1 OK and rule matches deny
* @retval 2 OK and rule matches permit
* @retval 1 OK and rule matches deny
* @retval 0 OK and rule does not match
* @retval -1 Error
*/
static int
nacm_data_write_xrule_xml(cxobj *xn,
@ -583,7 +591,8 @@ nacm_data_write_xrule_xml(cxobj *xn,
}
/*! Recursive check for NACM write rules among all XML nodes
* @param[in] h Clicon handle
*
* @param[in] h Clixon handle
* @param[in] xn XML node (requested node)
* @param[in] rulevec Precomputed rules that apply to this user group
* @param[in] xpathvec Precomputed xpath results that apply to this XML tree
@ -592,7 +601,7 @@ nacm_data_write_xrule_xml(cxobj *xn,
* @param[out] cbret Error message if retval = 0
* @retval 1 OK and accept
* @retval 0 Deny and cbret set
* @retval -1 Error
* @retval -1 Error
* XXX differentiate between nomatch: default. or match deny, match accept
* nomatch: check write-default rules, next v
* accept: Hunky dory
@ -610,13 +619,13 @@ nacm_datanode_write_recurse(clicon_handle h,
cxobj *x;
int ret = 0;
prepvec *pv;
pv = pv_list;
if (pv){
do {
/* return values: -1:Error /0:no match /1: deny /2: permit
*/
if ((ret = nacm_data_write_xrule_xml(xn, pv->pv_xrule, pv->pv_xpathvec, yspec)) < 0)
if ((ret = nacm_data_write_xrule_xml(xn, pv->pv_xrule, pv->pv_xpathvec, yspec)) < 0)
goto done;
switch(ret){
case 0: /* No match, continue with next rule */
@ -658,6 +667,7 @@ nacm_datanode_write_recurse(clicon_handle h,
}
/*! Make nacm datanode and module rule write access validation
*
* The operations of NACM are: create, read, update, delete, exec
* where write is short-hand for create+delete+update
* @param[in] h Clixon handle
@ -666,10 +676,10 @@ nacm_datanode_write_recurse(clicon_handle h,
* @param[in] op NACM access of xreq
* @param[in] username User making access
* @param[in] xnacm NACM xml tree
* @param[out] cbret Cligen buffer result. Set to an error msg if retval=0.
* @retval -1 Error
* @retval 0 Not access and cbret set
* @retval 1 Access
* @param[out] cbret Cligen buffer result. Set to an error msg if retval=0.
* @retval 1 Access
* @retval 0 Not access and cbret set
* @retval -1 Error
* @see RFC8341 3.4.5. Data Node Access Validation
* @see nacm_datanode_read
* @see nacm_rpc
@ -738,7 +748,7 @@ nacm_datanode_write(clicon_handle h,
goto permit;
/* 8. At this point, no matching rule was found in any rule-list
entry. */
step9:
step9:
/* 10. For a "write" access operation, if the requested data node is
defined in a YANG module advertised in the server capabilities
and the data definition statement contains a
@ -759,7 +769,7 @@ nacm_datanode_write(clicon_handle h,
permit:
retval = 1;
done:
clicon_debug(1, "%s retval:%d (0:deny 1:permit)", __FUNCTION__, retval);
clixon_debug(CLIXON_DBG_DEFAULT, "%s retval:%d (0:deny 1:permit)", __FUNCTION__, retval);
if (pv_list)
prepvec_free(pv_list);
if (nsc)
@ -782,10 +792,12 @@ nacm_datanode_write(clicon_handle h,
*/
/*! Perform NACM action: mark if permit, del if deny
*
* @param[in] xrule NACM rule
* @param[in] xn XML node (requested node)
* @retval -1 Error
* @retval 0 OK
* @retval -1 Error
*/
static int
nacm_data_read_action(cxobj *xrule,
@ -806,12 +818,13 @@ nacm_data_read_action(cxobj *xrule,
}
/*! Match specific rule to specific requested node
*
* @param[in] xn XML node (requested node)
* @param[in] xrule NACM rule
* @param[in] yspec YANG spec
* @retval -1 Error
* @retval 0 OK and rule does not match
* @retval 1 OK and rule matches
* @retval 1 OK and rule matches
* @retval 0 OK and rule does not match
* @retval -1 Error
* Two distinct cases:
* (1) read_default is permit
* mark all deny rules and remove them
@ -829,7 +842,7 @@ nacm_data_read_xrule_xml(cxobj *xn,
char *module_pattern; /* rule module name */
cxobj *xp;
int i;
if ((module_pattern = xml_find_body(xrule, "module-name")) == NULL)
goto nomatch;
/* 6a) The rule's "module-name" leaf is "*" or equals the name of
@ -868,13 +881,14 @@ nacm_data_read_xrule_xml(cxobj *xn,
}
/*! Recursive check for NACM read rules among all XML nodes
* @param[in] h Clicon handle
*
* @param[in] h Clixon handle
* @param[in] xn XML node (requested node)
* @param[in] rulevec Precomputed rules that apply to this user group
* @param[in] xpathvec Precomputed xpath results that apply to this XML tree
* @param[in] yspec YANG spec
* @retval 0 OK
* @retval -1 Error
* @retval 0 OK
* @retval -1 Error
*/
static int
nacm_datanode_read_recurse(clicon_handle h,
@ -887,7 +901,7 @@ nacm_datanode_read_recurse(clicon_handle h,
cxobj *xprev;
int ret;
prepvec *pv;
if (xml_spec(xn)){ /* Check this node */
pv = pv_list;
if (pv){
@ -895,15 +909,15 @@ nacm_datanode_read_recurse(clicon_handle h,
if ((ret = nacm_data_read_xrule_xml(xn,
pv->pv_xrule,
pv->pv_xpathvec,
yspec)) < 0)
goto done;
yspec)) < 0)
goto done;
if (ret == 1)
break; /* stop at first match */
break; /* stop at first match */
pv = NEXTQ(prepvec *, pv);
} while (pv && pv != pv_list);
}
#if 0 /* 6(A) in algorithm
#if 0 /* 6(A) in algorithm
* If N did not match any rule R, and default rule is deny, remove that subtree */
if (strcmp(read_default, "deny") == 0)
if (xml_tree_prune_flagged_sub(xt, XML_FLAG_MARK, 1, NULL) < 0)
@ -932,16 +946,17 @@ nacm_datanode_read_recurse(clicon_handle h,
}
/*! Make nacm datanode and module rule read access validation
*
* Just purge nodes that fail validation (dont send netconf error message)
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] xt XML root tree with "config" label
* @param[in] xrvec Vector of requested nodes (sub-part of xt)
* @param[in] xrlen Length of requsted node vector
* @param[in] username
* @param[in] xnacm NACM xml tree
* @retval -1 Error
* @retval 0 Not access and cbret set
* @retval 1 Access
* @retval 1 Access
* @retval 0 Not access and cbret set
* @retval -1 Error
* 3.2.4: <get> and <get-config> Operations
* Data nodes to which the client does not have read access are silently
* omitted, along with any descendants, from the <rpc-reply> message.
@ -983,7 +998,7 @@ int
nacm_datanode_read(clicon_handle h,
cxobj *xt,
cxobj **xrvec,
size_t xrlen,
size_t xrlen,
char *username,
cxobj *xnacm)
{
@ -996,7 +1011,7 @@ nacm_datanode_read(clicon_handle h,
char *read_default = NULL;
cvec *nsc = NULL;
prepvec *pv_list = NULL;
/* Create namespace context for with nacm namespace as default */
if ((nsc = xml_nsctx_init(NULL, NACM_NS)) == NULL)
goto done;
@ -1059,7 +1074,7 @@ nacm_datanode_read(clicon_handle h,
ok:
retval = 0;
done:
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
clixon_debug(CLIXON_DBG_DEFAULT, "%s retval:%d", __FUNCTION__, retval);
if (pv_list)
prepvec_free(pv_list);
if (nsc)
@ -1077,15 +1092,16 @@ nacm_datanode_read(clicon_handle h,
*/
/*! NACM intial pre- access control enforcements
*
* Initial NACM steps and common to all NACM access validation.
* If retval=0 continue with next NACM step, eg rpc, module,
* etc. If retval = 1 access is OK and skip next NACM step.
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] xnacm NACM XML tree, root should be "nacm"
* @param[in] username User name of requestor
* @retval -1 Error
* @retval 0 OK but not validated. Need to do NACM step using xnacm
* @retval 1 OK permitted. You do not need to do next NACM step
* @retval 1 OK permitted. You do not need to do next NACM step
* @retval 0 OK but not validated. Need to do NACM step using xnacm
* @retval -1 Error
* @code
* if ((ret = nacm_access_check(h, mode, xnacm, peername, username)) < 0)
* err;
@ -1109,9 +1125,9 @@ nacm_access_check(clicon_handle h,
char *recovery_user;
#ifdef WITH_RESTCONF
char *wwwuser;
#endif
#endif
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
if ((nsc = xml_nsctx_init(NULL, NACM_NS)) == NULL)
goto done;
/* Do initial nacm processing common to all access validation in
@ -1164,23 +1180,24 @@ nacm_access_check(clicon_handle h,
done:
if (nsc)
xml_nsctx_free(nsc);
clicon_debug(1, "%s retval:%d (0:deny 1:permit)", __FUNCTION__, retval);
clixon_debug(CLIXON_DBG_DEFAULT, "%s retval:%d (0:deny 1:permit)", __FUNCTION__, retval);
return retval;
permit:
retval = 1;
goto done;
}
/*! NACM intial pre- access control enforcements
/*! NACM intial pre- access control enforcements
*
* Initial NACM steps and common to all NACM access validation.
* If retval=0 continue with next NACM step, eg rpc, module,
* etc. If retval = 1 access is OK and skip next NACM step.
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] username User name of requestor
* @param[out] xncam NACM XML tree, set if retval=0. Free after use
* @retval -1 Error
* @retval 0 OK but not validated. Need to do NACM step using xnacm
* @retval 1 OK permitted. You do not need to do next NACM step.
* @retval 1 OK permitted. You do not need to do next NACM step.
* @retval 0 OK but not validated. Need to do NACM step using xnacm
* @retval -1 Error
* @code
* cxobj *xnacm = NULL;
* if ((ret = nacm_access_pre(h, peername, username, &xnacm)) < 0)
@ -1204,7 +1221,7 @@ nacm_access_pre(clicon_handle h,
cxobj *xnacm0 = NULL;
cxobj *xnacm = NULL;
cvec *nsc = NULL;
/* Check clixon option: disabled, external tree or internal */
mode = clicon_option_str(h, "CLICON_NACM_MODE");
if (mode == NULL)
@ -1224,7 +1241,6 @@ nacm_access_pre(clicon_handle h,
clicon_err(OE_XML, 0, "Invalid NACM mode: %s", mode);
goto done;
}
if ((nsc = xml_nsctx_init(NULL, NACM_NS)) == NULL)
goto done;
/* If config does not exist then the operation is permitted(?) */
@ -1263,9 +1279,9 @@ nacm_access_pre(clicon_handle h,
* @param[in] peername Peer username if any
* @param[in] username username received in XML (eg for NACM)
* @param[out] cbret Set with netconf error message if ret == 0
* @retval -1 Error
* @retval 0 Not verified (cbret set)
* @retval 1 Verified
* @retval 0 Not verified (cbret set)
* @retval -1 Error
* Credentials OK if
* - cred mode is NONE,
* Otherwise both NACM user AND peer user must exist, and
@ -1287,7 +1303,7 @@ verify_nacm_user(clicon_handle h,
cbuf *cbmsg = NULL;
#ifdef WITH_RESTCONF
char *wwwuser;
#endif
#endif
if (cred == NC_NONE)
return 1;
@ -1300,7 +1316,7 @@ verify_nacm_user(clicon_handle h,
if (netconf_access_denied(cbret, "application", "No NACM available") < 0)
goto done;
goto fail;
}
}
if (cred == NC_EXCEPT){
if (strcmp(peername, "root") == 0)
goto ok;

View file

@ -92,7 +92,7 @@ netconf_input_read2(int s,
{
int retval = -1;
ssize_t len;
memset(buf, 0, buflen);
if ((len = read(s, buf, buflen)) < 0){
if (errno == ECONNRESET)
@ -102,14 +102,14 @@ netconf_input_read2(int s,
goto done;
}
} /* read */
clicon_debug(CLIXON_DBG_DETAIL, "%s len:%ld", __FUNCTION__, len);
clixon_debug(CLIXON_DBG_DETAIL, "%s len:%ld", __FUNCTION__, len);
if (len == 0){ /* EOF */
clicon_debug(CLIXON_DBG_DETAIL, "%s len==0, closing", __FUNCTION__);
clixon_debug(CLIXON_DBG_DETAIL, "%s len==0, closing", __FUNCTION__);
*eof = 1;
}
retval = len;
done:
clicon_debug(CLIXON_DBG_DETAIL, "%s retval:%d", __FUNCTION__, retval);
clixon_debug(CLIXON_DBG_DETAIL, "%s retval:%d", __FUNCTION__, retval);
return retval;
}
@ -146,7 +146,7 @@ netconf_input_msg2(unsigned char **bufp,
size_t len;
char ch;
clicon_debug(CLIXON_DBG_DETAIL, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DETAIL, "%s", __FUNCTION__);
len = *lenp;
for (i=0; i<len; i++){
if ((ch = (*bufp)[i]) == 0)
@ -189,7 +189,7 @@ netconf_input_msg2(unsigned char **bufp,
*eom = found;
retval = 0;
done:
clicon_debug(CLIXON_DBG_DETAIL, "%s retval:%d", __FUNCTION__, retval);
clixon_debug(CLIXON_DBG_DETAIL, "%s retval:%d", __FUNCTION__, retval);
return retval;
}
@ -217,14 +217,14 @@ netconf_input_frame2(cbuf *cb,
cxobj *xtop = NULL; /* Request (in) */
int ret;
clicon_debug(CLIXON_DBG_DETAIL, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DETAIL, "%s", __FUNCTION__);
if (xrecv == NULL){
clicon_err(OE_PLUGIN, EINVAL, "xrecv is NULL");
goto done;
}
str = cbuf_get(cb);
/* Special case: empty XML */
if (strlen(str) == 0){
if (strlen(str) == 0){
if (netconf_operation_failed_xml(xerr, "rpc", "Empty XML")< 0)
goto done;
goto failed;

View file

@ -87,6 +87,7 @@ static const map_str2int wdmap[] = {
};
/*! Map from with-defaults ints to strings
*
* @param[in] int Integer representation of withdefaults values
* @retval str String representation of withdefaults values
*/
@ -97,6 +98,7 @@ withdefaults_int2str(int keyword)
}
/*! Map from with-defaults strings to ints
*
* @param[in] str String representation of withdefaults values
* @retval int Integer representation of withdefaults values
*/
@ -112,6 +114,8 @@ withdefaults_str2int(char *str)
* @param[out] cb CLIgen buf. Error XML is written in this buffer
* @param[in] type Error type: "application" or "protocol"
* @param[in] message Error message (will be XML encoded)
* @retval 0 OK
* @retval -1 Error
*/
int
netconf_in_use(cbuf *cb,
@ -152,6 +156,8 @@ netconf_in_use(cbuf *cb,
* @param[out] xret Error XML tree. Free with xml_free after use
* @param[in] type Error type: "application" or "protocol"
* @param[in] message Error message (will be XML encoded)
* @retval 0 OK
* @retval -1 Error
*/
int
netconf_invalid_value_xml(cxobj **xret,
@ -201,6 +207,8 @@ netconf_invalid_value_xml(cxobj **xret,
* @param[out] cb CLIgen buf. Error XML is written in this buffer
* @param[in] type Error type: "application" or "protocol"
* @param[in] message Error message (will be XML encoded)
* @retval 0 OK
* @retval -1 Error
*/
int
netconf_invalid_value(cbuf *cb,
@ -228,6 +236,8 @@ netconf_invalid_value(cbuf *cb,
* @param[out] cb CLIgen buf. Error XML is written in this buffer
* @param[in] type Error type: "transport", "rpc", "application", "protocol"
* @param[in] message Error message (will be XML encoded)
* @retval 0 OK
* @retval -1 Error
*/
int
netconf_too_big(cbuf *cb,
@ -269,6 +279,8 @@ netconf_too_big(cbuf *cb,
* @param[in] type Error type: "rpc", "application" or "protocol"
* @param[in] attr bad-attribute and/or bad-element xml
* @param[in] message Error message (will be XML encoded)
* @retval 0 OK
* @retval -1 Error
*/
int
netconf_missing_attribute_xml(cxobj **xret,
@ -320,6 +332,8 @@ netconf_missing_attribute_xml(cxobj **xret,
* @param[in] type Error type: "rpc", "application" or "protocol"
* @param[in] attr bad-attribute
* @param[in] message Error message (will be XML encoded) or NULL
* @retval 0 OK
* @retval -1 Error
*/
int
netconf_missing_attribute(cbuf *cb,
@ -349,6 +363,8 @@ netconf_missing_attribute(cbuf *cb,
* @param[in] type Error type: "rpc", "application" or "protocol"
* @param[in] info Attribute name
* @param[in] message Error message (will be XML encoded)
* @retval 0 OK
* @retval -1 Error
*/
int
netconf_bad_attribute(cbuf *cb,
@ -378,6 +394,9 @@ netconf_bad_attribute(cbuf *cb,
* @param[in] type Error type: "rpc", "application" or "protocol"
* @param[in] info Attribute name
* @param[in] message Error message (will be XML encoded)
* @retval 0 OK
* @retval -1 Error
*/
int
netconf_bad_attribute_xml(cxobj **xret,
@ -429,6 +448,8 @@ netconf_bad_attribute_xml(cxobj **xret,
* @param[in] type Error type: "rpc", "application" or "protocol"
* @param[in] info bad-attribute or bad-element xml
* @param[in] message Error message
* @retval 0 OK
* @retval -1 Error
*/
int
netconf_unknown_attribute(cbuf *cb,
@ -471,6 +492,8 @@ netconf_unknown_attribute(cbuf *cb,
* @param[in] tag Error tag
* @param[in] element bad-element xml
* @param[in] message Error message (will be XML encoded)
* @retval 0 OK
* @retval -1 Error
*/
static int
netconf_common_xml(cxobj **xret,
@ -525,6 +548,8 @@ netconf_common_xml(cxobj **xret,
* @param[in] type Error type: "application" or "protocol"
* @param[in] info bad-element xml
* @param[in] message Error message
* @retval 0 OK
* @retval -1 Error
*/
int
netconf_missing_element(cbuf *cb,
@ -552,6 +577,8 @@ netconf_missing_element(cbuf *cb,
* @param[in] type Error type: "application" or "protocol"
* @param[in] element bad-element xml
* @param[in] message Error message
* @retval 0 OK
* @retval -1 Error
*/
int
netconf_missing_element_xml(cxobj **xret,
@ -571,6 +598,8 @@ netconf_missing_element_xml(cxobj **xret,
* @param[in] type Error type: "application" or "protocol"
* @param[in] elemnt Bad element name
* @param[in] message Error message
* @retval 0 OK
* @retval -1 Error
*/
int
netconf_bad_element(cbuf *cb,
@ -609,6 +638,8 @@ netconf_bad_element_xml(cxobj **xret,
* @param[in] type Error type: "application" or "protocol"
* @param[in] element Bad element name
* @param[in] message Error message
* @retval 0 OK
* @retval -1 Error
*/
int
netconf_unknown_element(cbuf *cb,
@ -638,6 +669,8 @@ netconf_unknown_element(cbuf *cb,
* @param[in] type Error type: "application" or "protocol"
* @param[in] element Bad element name
* @param[in] message Error message
* @retval 0 OK
* @retval -1 Error
*/
int
netconf_unknown_element_xml(cxobj **xret,
@ -656,6 +689,8 @@ netconf_unknown_element_xml(cxobj **xret,
* @param[in] type Error type: "application" or "protocol"
* @param[in] info bad-element or bad-namespace xml
* @param[in] message Error message
* @retval 0 OK
* @retval -1 Error
*/
int
netconf_unknown_namespace(cbuf *cb,
@ -695,6 +730,8 @@ netconf_unknown_namespace_xml(cxobj **xret,
* @param[out] cb CLIgen buf. Error XML is written in this buffer
* @param[in] type Error type: "application" or "protocol"
* @param[in] message Error message
* @retval 0 OK
* @retval -1 Error
* @see netconf_access_denied_xml Same but returns XML tree
*/
int
@ -723,6 +760,8 @@ netconf_access_denied(cbuf *cb,
* @param[out] xret Error XML tree. Free with xml_free after use
* @param[in] type Error type: "application" or "protocol"
* @param[in] message Error message (will be XML encoded)
* @retval 0 OK
* @retval -1 Error
* @code
* cxobj *xret = NULL;
* if (netconf_access_denied_xml(&xret, "protocol", "Unauthorized") < 0)
@ -779,6 +818,8 @@ netconf_access_denied_xml(cxobj **xret,
* @param[out] cb CLIgen buf. Error XML is written in this buffer
* @param[in] info session-id xml
* @param[in] message Error message
* @retval 0 OK
* @retval -1 Error
*/
int
netconf_lock_denied(cbuf *cb,
@ -819,6 +860,8 @@ netconf_lock_denied(cbuf *cb,
* @param[out] cb CLIgen buf. Error XML is written in this buffer
* @param[in] type Error type: "transport, "rpc", "application", "protocol"
* @param[in] message Error message
* @retval 0 OK
* @retval -1 Error
*/
int
netconf_resource_denied(cbuf *cb,
@ -859,6 +902,8 @@ netconf_resource_denied(cbuf *cb,
* @param[out] cb CLIgen buf. Error XML is written in this buffer
* @param[in] type Error type: "application" or "protocol"
* @param[in] message Error message
* @retval 0 OK
* @retval -1 Error
*/
int
netconf_rollback_failed(cbuf *cb,
@ -899,6 +944,8 @@ netconf_rollback_failed(cbuf *cb,
* a "create" operation was attempted on data that already exists.
* @param[out] cb CLIgen buf. Error XML is written in this buffer
* @param[in] message Error message
* @retval 0 OK
* @retval -1 Error
*/
int
netconf_data_exists(cbuf *cb,
@ -938,6 +985,8 @@ netconf_data_exists(cbuf *cb,
* data that does not exist.
* @param[out] cb CLIgen buf. Error XML is written in this buffer
* @param[in] message Error message
* @retval 0 OK
* @retval -1 Error
*/
int
netconf_data_missing(cbuf *cb,
@ -964,6 +1013,8 @@ netconf_data_missing(cbuf *cb,
* data that does not exist.
* @param[out] xret Error XML tree. Free with xml_free after use
* @param[in] message Error message
* @retval 0 OK
* @retval -1 Error
*/
int
netconf_data_missing_xml(cxobj **xret,
@ -1017,6 +1068,8 @@ netconf_data_missing_xml(cxobj **xret,
* @param[in] x Element with missing choice
* @param[in] name Name of missing mandatory choice
* @param[in] message Error message
* @retval 0 OK
* @retval -1 Error
*/
int
netconf_missing_choice_xml(cxobj **xret,
@ -1085,6 +1138,8 @@ netconf_missing_choice_xml(cxobj **xret,
* @param[out] xret Error XML tree
* @param[in] type Error type: "application" or "protocol"
* @param[in] message Error message
* @retval 0 OK
* @retval -1 Error
* @code
* cxobj *xret = NULL;
* if (netconf_operation_not_supported_xml(&xret, "protocol", "Unauthorized") < 0)
@ -1142,6 +1197,8 @@ netconf_operation_not_supported_xml(cxobj **xret,
* @param[out] cb CLIgen buf. Error XML is written in this buffer
* @param[in] type Error type: "application" or "protocol"
* @param[in] message Error message
* @retval 0 OK
* @retval -1 Error
*/
int
netconf_operation_not_supported(cbuf *cb,
@ -1169,6 +1226,8 @@ netconf_operation_not_supported(cbuf *cb,
* @param[out] cb CLIgen buf. Error XML is written in this buffer
* @param[in] type Error type: "rpc", "application" or "protocol"
* @param[in] message Error message (will be XML encoded)
* @retval 0 OK
* @retval -1 Error
* @see netconf_operation_failed_xml Same but returns XML tree
*/
int
@ -1197,6 +1256,8 @@ netconf_operation_failed(cbuf *cb,
* @param[out] xret Error XML tree
* @param[in] type Error type: "rpc", "application" or "protocol"
* @param[in] message Error message (will be XML encoded)
* @retval 0 OK
* @retval -1 Error
* @code
* cxobj *xret = NULL;
* if (netconf_operation_failed_xml(&xret, "protocol", "Unauthorized") < 0)
@ -1254,6 +1315,8 @@ netconf_operation_failed_xml(cxobj **xret,
* invalid character set.
* @param[out] cb CLIgen buf. Error XML is written in this buffer
* @param[in] message Error message
* @retval 0 OK
* @retval -1 Error
* @note New in :base:1.1
* @see netconf_malformed_message_xml Same but returns XML tree
*/
@ -1282,6 +1345,8 @@ netconf_malformed_message(cbuf *cb,
* invalid character set.
* @param[out] xret Error XML tree
* @param[in] message Error message (will be XML encoded)
* @retval 0 OK
* @retval -1 Error
* @note New in :base:1.1
* @code
* cxobj *xret = NULL;
@ -1338,6 +1403,8 @@ netconf_malformed_message_xml(cxobj **xret,
* @param[out] xret Error XML tree. Free with xml_free after use
* @param[in] x List element containing duplicate
* @param[in] cvk List of components in x that are non-unique
* @retval 0 OK
* @retval -1 Error
* @see RFC7950 Sec 15.1
* @see netconf_data_not_unique_xml Same but returns XML tree
*/
@ -1367,6 +1434,8 @@ netconf_data_not_unique(cbuf *cb,
* @param[out] xret Error XML tree. Free with xml_free after use
* @param[in] x List element containing duplicate
* @param[in] cvk List of components in x that are non-unique
* @retval 0 OK
* @retval -1 Error
* @see RFC7950 Sec 15.1
*/
int
@ -1437,6 +1506,8 @@ netconf_data_not_unique_xml(cxobj **xret,
* @param[in] xp XML parent node (for error)
* @param[in] name Name of list (for error)
* @param[in] max If set, return too-many, otherwise too-few
* @retval 0 OK
* @retval -1 Error
* @see RFC7950 Sec 15.1
*/
int
@ -1489,6 +1560,7 @@ netconf_minmax_elements_xml(cxobj **xret,
}
/*! Help function: merge - check yang - if error make netconf errmsg
*
* @param[in] x XML tree
* @param[in] yspec Yang spec
* @param[in,out] xret Existing XML tree, merge x into this
@ -1574,6 +1646,7 @@ netconf_module_features(clicon_handle h)
}
/*! Load generic yang specs, ie ietf netconf yang module and set enabled features
*
* @param[in] h Clixon handle
* @retval 0 OK
* @retval -1 Error
@ -1642,6 +1715,7 @@ netconf_module_load(clicon_handle h)
}
/*! Find some sub-child in netconf/xm request.
*
* Actually, find a child with a certain name and return its body
* @param[in] xn
* @param[in] name
@ -1674,6 +1748,7 @@ netconf_db_find(cxobj *xn,
}
/*! Generate netconf error msg to cbuf to use in string printout or logs
*
* @param[in] xerr Netconf error message on the level: <rpc-error>
* @param[in,out] cberr Translation from netconf err to cbuf.
* @retval 0 OK, with cberr set
@ -1830,9 +1905,12 @@ netconf_capabilites(clicon_handle h,
}
/*! Create Netconf server hello. Single cap and defer individual to querying modules
* @param[in] h Clicon handle
*
* @param[in] h Clixon handle
* @param[in] cb Msg buffer
* @param[in] session_id Id of client session
* @retval 0 OK
* @retval -1 Error
* Lots of dependencies here. regarding the hello protocol.
* RFC6241 NETCONF Protocol says: (8.1)
* MUST send a <hello> element containing a list of that peer's capabilities
@ -1880,6 +1958,8 @@ netconf_hello_server(clicon_handle h,
* @param[in] xerr Netconf error xml tree on the form: <rpc-error>
* @param[in] format Format string
* @param[in] arg String argument to format (optional)
* @retval 0 OK
* @retval -1 Error
* @see netconf_err2cb
*/
int
@ -1928,7 +2008,7 @@ clixon_netconf_error_fn(const char *fn,
* @param[in] msg Error message
* @param[in] arg Extra error message (consider stdarg?)
* @retval 0 OK
* @retval -1 Error
* @retval -1 Error
*/
int
clixon_netconf_internal_error(cxobj *xerr,
@ -2022,6 +2102,7 @@ netconf_parse_uint32(char *name,
}
/*! Parse string into uint32 and return netconf bad-element msg on error xml variant
*
* @see netconf_parse_uint32_xml
*/
int
@ -2089,7 +2170,9 @@ netconf_message_id_next(clicon_handle h)
/*! Add netconf xml postamble of message. I.e, xml after the body of the message.
*
* @param[in] framing Netconf framing
* @param[in,out] cb Netconf packet (cligen buffer)
* @param[in,out] cb Netconf packet (cligen buffer)
* @retval 0 OK
* @retval -1 Error
* XXX: copies body
*/
int
@ -2140,6 +2223,7 @@ netconf_framing_postamble(netconf_framing_type framing,
}
/*! Send netconf message from cbuf on socket
*
* @param[in] s
* @param[in] cb Cligen buffer that contains the XML message
* @param[in] msg Only for debug
@ -2156,7 +2240,7 @@ netconf_output(int s,
char *buf = cbuf_get(cb);
int len = cbuf_len(cb);
clicon_debug(CLIXON_DBG_MSG, "Send ext: %s", cbuf_get(cb));
clixon_debug(CLIXON_DBG_MSG, "Send ext: %s", cbuf_get(cb));
#if 0 // Extra sanity check for debugging
{
cxobj *xt = NULL;
@ -2170,7 +2254,7 @@ netconf_output(int s,
#endif
if (write(s, buf, len) < 0){
if (errno == EPIPE)
clicon_debug(1, "%s write err SIGPIPE", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s write err SIGPIPE", __FUNCTION__);
else
clicon_log(LOG_ERR, "%s: write: %s", __FUNCTION__, strerror(errno));
goto done;
@ -2252,7 +2336,7 @@ netconf_input_chunked_framing(char ch,
{
int retval = 0;
clicon_debug(CLIXON_DBG_DETAIL, "%s ch:%c(%d) state:%d size:%zu", __FUNCTION__, ch, ch, *state, *size);
clixon_debug(CLIXON_DBG_DETAIL, "%s ch:%c(%d) state:%d size:%zu", __FUNCTION__, ch, ch, *state, *size);
switch (*state){
case 0:
if (ch == '\n'){
@ -2290,7 +2374,7 @@ netconf_input_chunked_framing(char ch,
*size = (*size)*10 + ch-'0';
break;
}
else if (ch == '\n'){
else if (ch == '\n'){
(*state)++;
break;
}

View file

@ -99,7 +99,7 @@ per_datastore(clicon_handle h,
/*! Get netconf monitoring datastore state
*
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] yspec Yang spec
* @param[in,out] cb CLIgen buffer
* @retval 0 OK
@ -130,7 +130,7 @@ netconf_monitoring_datastores(clicon_handle h,
/*! Get netconf monitoring schema state
*
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] yspec Yang spec
* @param[in,out] cb CLIgen buffer
* @retval 0 OK
@ -181,7 +181,7 @@ netconf_monitoring_schemas(clicon_handle h,
/*! Get netconf monitoring statistics state
*
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] yspec Yang spec
* @param[in,out] cb CLIgen buffer
* @retval 0 OK
@ -197,7 +197,7 @@ netconf_monitoring_statistics(clicon_handle h,
char *str;
cvec *cvv = NULL;
cg_var *cv;
cprintf(cb, "<statistics>");
if (clicon_data_get(h, "netconf-start-time", &str) == 0 &&
str != NULL){
@ -230,7 +230,7 @@ netconf_monitoring_statistics(clicon_handle h,
*
* Netconf monitoring state is:
* capabilities, datastores, schemas, sessions, statistics
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] yspec Yang spec
* @param[in] xpath XML Xpath
* @param[in] nsc XML Namespace context for xpath
@ -253,7 +253,7 @@ netconf_monitoring_state_get(clicon_handle h,
int retval = -1;
cbuf *cb = NULL;
int ret;
if ((cb = cbuf_new()) ==NULL){
clicon_err(OE_XML, errno, "cbuf_new");
goto done;
@ -276,7 +276,7 @@ netconf_monitoring_state_get(clicon_handle h,
}
retval = 1;
done:
clicon_debug(1, "%s %d", __FUNCTION__, retval);
clixon_debug(CLIXON_DBG_DEFAULT, "%s %d", __FUNCTION__, retval);
if (cb)
cbuf_free(cb);
return retval;
@ -289,6 +289,8 @@ netconf_monitoring_state_get(clicon_handle h,
*
* @param[in] cvv Cligen vector
* @param[in] name Name of new counter
* @retval 0 OK
* @retval -1 Error
*/
static int
stat_counter_add(cvec *cvv,
@ -310,7 +312,9 @@ stat_counter_add(cvec *cvv,
/*! Init RFC6022 stats
*
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @retval 0 OK
* @retval -1 Error
*/
int
netconf_monitoring_statistics_init(clicon_handle h)
@ -353,12 +357,12 @@ netconf_monitoring_statistics_init(clicon_handle h)
*
* @param[in] h Clixon handle
* @param[in] name Name of counter
* @retval 0 OK
*/
int
netconf_monitoring_counter_inc(clicon_handle h,
char *name)
{
int retval = -1;
cvec *cvv = NULL;
cg_var *cv;
uint32_t u32;
@ -370,6 +374,5 @@ netconf_monitoring_counter_inc(clicon_handle h,
cv_uint32_set(cv, u32);
}
}
retval = 0;
return retval;
return 0;
}

View file

@ -109,16 +109,19 @@ get_sock(int usock,
#endif /* HAVE_SETNS */
/*! Create and bind stream socket
*
* @param[in] sa Socketaddress
* @param[in] sa_len Length of sa. Tecynicaliyu to be independent of sockaddr sa_len
* @param[in] backlog Listen backlog, queie of pending connections
* @param[in] flags Socket flags Or:ed in with the socket(2) type parameter
* @param[in] addrstr Address string for debug
* @param[out] sock Server socket (bound for accept)
* @retval 0 OK
* @retval -1 Error
*/
static int
create_socket(struct sockaddr *sa,
size_t sin_len,
size_t sin_len,
int backlog,
int flags,
const char *addrstr,
@ -127,8 +130,8 @@ create_socket(struct sockaddr *sa,
int retval = -1;
int s = -1;
int on = 1;
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
if (sock == NULL){
clicon_err(OE_PROTO, EINVAL, "Requires socket output parameter");
goto done;
@ -182,7 +185,7 @@ create_socket(struct sockaddr *sa,
*sock = s;
retval = 0;
done:
clicon_debug(1, "%s %d", __FUNCTION__, retval);
clixon_debug(CLIXON_DBG_DEFAULT, "%s %d", __FUNCTION__, retval);
if (retval != 0 && s != -1)
close(s);
return retval;
@ -198,11 +201,13 @@ create_socket(struct sockaddr *sa,
* @param[in] flags Socket flags OR:ed in with the socket(2) type parameter
* @param[in] addrstr Address string for debug
* @param[out] sock Server socket (bound for accept)
* @retval 0 OK
* @retval -1 Error
*/
static int
fork_netns_socket(const char *netns,
struct sockaddr *sa,
size_t sin_len,
size_t sin_len,
int backlog,
int flags,
const char *addrstr,
@ -221,7 +226,7 @@ fork_netns_socket(const char *netns,
int sock_flags = SOCK_DGRAM | SOCK_CLOEXEC;
#endif
clicon_debug(1, "%s %s", __FUNCTION__, netns);
clixon_debug(CLIXON_DBG_DEFAULT, "%s %s", __FUNCTION__, netns);
if (socketpair(AF_UNIX, sock_flags, 0, sp) < 0){
clicon_err(OE_UNIX, errno, "socketpair");
goto done;
@ -240,7 +245,7 @@ fork_netns_socket(const char *netns,
#endif
/* Check namespace exists */
sprintf(nspath,"/var/run/netns/%s", netns);
sprintf(nspath,"/var/run/netns/%s", netns);
if (stat(nspath, &st) < 0){
clicon_err(OE_UNIX, errno, ": stat(%s)", nspath);
goto done;
@ -288,19 +293,20 @@ fork_netns_socket(const char *netns,
if(waitpid(child, &wstatus, 0) == child)
; // retval = WEXITSTATUS(status); /* Dont know what to do with status */
if (WEXITSTATUS(wstatus)){
clicon_debug(1, "%s wstatus:%d", __FUNCTION__, WEXITSTATUS(wstatus));
clixon_debug(CLIXON_DBG_DEFAULT, "%s wstatus:%d", __FUNCTION__, WEXITSTATUS(wstatus));
*sock = -1;
clicon_err(OE_UNIX, EADDRNOTAVAIL, "bind(%s)", addrstr);
goto done;
}
retval = 0;
done:
clicon_debug(1, "%s %d", __FUNCTION__, retval);
clixon_debug(CLIXON_DBG_DEFAULT, "%s %d", __FUNCTION__, retval);
return retval;
}
#endif /* HAVE_SETNS */
/*! Create and bind stream socket in network namespace
*
* @param[in] netns Network namespace
* @param[in] sa Socketaddress
* @param[in] sa_len Length of sa. Tecynicaliyu to be independent of sockaddr sa_len
@ -308,19 +314,21 @@ fork_netns_socket(const char *netns,
* @param[in] flags Socket flags OR:ed in with the socket(2) type parameter
* @param[in] addrstr Address string for debug
* @param[out] sock Server socket (bound for accept)
* @retval 0 OK
* @retval -1 Error
*/
int
clixon_netns_socket(const char *netns,
struct sockaddr *sa,
size_t sin_len,
size_t sin_len,
int backlog,
int flags,
const char *addrstr,
int *sock)
{
int retval = -1;
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
if (netns == NULL){
if (create_socket(sa, sin_len, backlog, flags, addrstr, sock) < 0)
goto done;
@ -332,12 +340,12 @@ clixon_netns_socket(const char *netns,
goto done;
#else
clicon_err(OE_UNIX, errno, "No namespace support on platform: %s", netns);
return -1;
return -1;
#endif
}
ok:
retval = 0;
done:
clicon_debug(1, "%s %d", __FUNCTION__, retval);
clixon_debug(CLIXON_DBG_DEFAULT, "%s %d", __FUNCTION__, retval);
return retval;
}

View file

@ -89,29 +89,29 @@
/* Mapping between Clicon startup modes string <--> constants,
see clixon-config.yang type startup_mode */
static const map_str2int startup_mode_map[] = {
{"none", SM_NONE},
{"init", SM_INIT},
{"running", SM_RUNNING},
{"none", SM_NONE},
{"init", SM_INIT},
{"running", SM_RUNNING},
{"startup", SM_STARTUP},
{"running-startup", SM_RUNNING_STARTUP},
{"running-startup", SM_RUNNING_STARTUP},
{NULL, -1}
};
/* Mapping between Clicon privileges modes string <--> constants,
* see clixon-config.yang type priv_mode */
static const map_str2int priv_mode_map[] = {
{"none", PM_NONE},
{"drop_perm", PM_DROP_PERM},
{"drop_temp", PM_DROP_TEMP},
{"none", PM_NONE},
{"drop_perm", PM_DROP_PERM},
{"drop_temp", PM_DROP_TEMP},
{NULL, -1}
};
/* Mapping between Clicon nacm user credential string <--> constants,
* see clixon-config.yang type nacm_cred_mode */
static const map_str2int nacm_credentials_map[] = {
{"none", NC_NONE},
{"exact", NC_EXACT},
{"except", NC_EXCEPT},
{"none", NC_NONE},
{"exact", NC_EXACT},
{"except", NC_EXCEPT},
{NULL, -1}
};
@ -132,10 +132,9 @@ static const map_str2int yang_regexp_map[] = {
{NULL, -1}
};
/*! Debug dump config options
*
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] dbglevel Debug level
* @retval 0 OK
* @retval -1 Error
@ -145,7 +144,7 @@ static const map_str2int yang_regexp_map[] = {
* @see cli_show_options
*/
int
clicon_option_dump(clicon_handle h,
clicon_option_dump(clicon_handle h,
int dbglevel)
{
int retval = -1;
@ -156,19 +155,19 @@ clicon_option_dump(clicon_handle h,
size_t klen;
size_t vlen;
cxobj *x = NULL;
if (clicon_hash_keys(hash, &keys, &klen) < 0)
goto done;
for(i = 0; i < klen; i++) {
val = clicon_hash_value(hash, keys[i], &vlen);
if (vlen){
if (((char*)val)[vlen-1]=='\0') /* assume string */
clicon_debug(dbglevel, "%s =\t \"%s\"", keys[i], (char*)val);
clixon_debug(dbglevel, "%s =\t \"%s\"", keys[i], (char*)val);
else
clicon_debug(dbglevel, "%s =\t 0x%p , length %zu", keys[i], val, vlen);
clixon_debug(dbglevel, "%s =\t 0x%p , length %zu", keys[i], val, vlen);
}
else
clicon_debug(dbglevel, "%s = NULL", keys[i]);
clixon_debug(dbglevel, "%s = NULL", keys[i]);
}
/* Next print CLICON_FEATURE, CLICON_YANG_DIR and CLICON_SNMP_DIR from config tree
* Since they are lists they are placed in the config tree.
@ -177,19 +176,19 @@ clicon_option_dump(clicon_handle h,
while ((x = xml_child_each(clicon_conf_xml(h), x, CX_ELMNT)) != NULL) {
if (strcmp(xml_name(x), "CLICON_YANG_DIR") != 0)
continue;
clicon_debug(dbglevel, "%s =\t \"%s\"", xml_name(x), xml_body(x));
clixon_debug(dbglevel, "%s =\t \"%s\"", xml_name(x), xml_body(x));
}
x = NULL;
while ((x = xml_child_each(clicon_conf_xml(h), x, CX_ELMNT)) != NULL) {
if (strcmp(xml_name(x), "CLICON_FEATURE") != 0)
continue;
clicon_debug(dbglevel, "%s =\t \"%s\"", xml_name(x), xml_body(x));
clixon_debug(dbglevel, "%s =\t \"%s\"", xml_name(x), xml_body(x));
}
x = NULL;
while ((x = xml_child_each(clicon_conf_xml(h), x, CX_ELMNT)) != NULL) {
if (strcmp(xml_name(x), "CLICON_SNMP_MIB") != 0)
continue;
clicon_debug(dbglevel, "%s =\t \"%s\"", xml_name(x), xml_body(x));
clixon_debug(dbglevel, "%s =\t \"%s\"", xml_name(x), xml_body(x));
}
retval = 0;
done:
@ -200,7 +199,7 @@ clicon_option_dump(clicon_handle h,
/*! Dump config options on stdio using output format
*
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] f Output file
* @param[in] format Dump output format
* @param[in] pretty Set if pretty-print xml and json
@ -209,7 +208,7 @@ clicon_option_dump(clicon_handle h,
* @see clicon_option_dump for debug log
*/
int
clicon_option_dump1(clicon_handle h,
clicon_option_dump1(clicon_handle h,
FILE *f,
int format,
int pretty)
@ -245,7 +244,9 @@ clicon_option_dump1(clicon_handle h,
*
* @param[in] filename
* @param[in] yspec
* @param[out] xconfig Pointer to xml config tree. Should be freed by caller
* @param[out] xconfig Pointer to xml config tree. Should be freed by caller
* @retval 0 OK
* @retval -1 Error
*/
static int
parse_configfile_one(const char *filename,
@ -264,7 +265,7 @@ parse_configfile_one(const char *filename,
clicon_err(OE_UNIX, errno, "open configure file: %s", filename);
return -1;
}
clicon_debug(CLIXON_DBG_DETAIL, "%s: Reading config file %s", __FUNCTION__, filename);
clixon_debug(CLIXON_DBG_DETAIL, "%s: Reading config file %s", __FUNCTION__, filename);
if ((ret = clixon_xml_parse_file(fp, yspec?YB_MODULE:YB_NONE, yspec, &xt, &xerr)) < 0)
goto done;
if (ret == 0){
@ -296,7 +297,7 @@ parse_configfile_one(const char *filename,
xt = NULL;
retval = 0;
done:
clicon_debug(CLIXON_DBG_DETAIL, "%s: Done w/ config file %s returning %d", __FUNCTION__, filename, retval);
clixon_debug(CLIXON_DBG_DETAIL, "%s: Done w/ config file %s returning %d", __FUNCTION__, filename, retval);
if (xt)
xml_free(xt);
if (fp)
@ -383,7 +384,7 @@ merge_control_xml(clicon_handle h,
static int
parse_configfile(clicon_handle h,
const char *filename,
char *extraconfdir0,
char *extraconfdir0,
yang_stmt *yspec,
cxobj **xconfig)
{
@ -421,7 +422,7 @@ parse_configfile(clicon_handle h,
goto done;
}
clicon_debug(CLIXON_DBG_DETAIL, "%s: Reading config file %s", __FUNCTION__, filename);
clixon_debug(CLIXON_DBG_DETAIL, "%s: Reading config file %s", __FUNCTION__, filename);
/* Parse main config file */
if (parse_configfile_one(filename, yspec, &xt) < 0)
goto done;
@ -441,7 +442,7 @@ parse_configfile(clicon_handle h,
if((ndp = clicon_file_dirent(extraconfdir, &dp, NULL, S_IFREG)) < 0) /* Read dir */
goto done;
/* Loop through files */
for (i = 0; i < ndp; i++){
for (i = 0; i < ndp; i++){
snprintf(filename1, sizeof(filename1), "%s/%s", extraconfdir, dp[i].d_name);
if (parse_configfile_one(filename1, yspec, &xe) < 0)
goto done;
@ -465,7 +466,7 @@ parse_configfile(clicon_handle h,
}
}
if (xml_default_recurse(xt, 0) < 0)
goto done;
goto done;
if ((ret = xml_yang_validate_add(h, xt, &xerr)) < 0)
goto done;
if (ret == 0){
@ -478,7 +479,7 @@ parse_configfile(clicon_handle h,
clicon_err(OE_CFG, 0, "Config file validation: %s", cbuf_get(cbret));
goto done;
}
/* Add top-level hash options.
/* Add top-level hash options.
* Hashed options are historical and could be replaced with xml, see eg clicon_option_str
*/
x = NULL;
@ -500,7 +501,7 @@ parse_configfile(clicon_handle h,
continue;
if (strcmp(name,"CLICON_SNMP_MIB")==0)
continue;
if (clicon_hash_add(copt,
if (clicon_hash_add(copt,
name,
body,
strlen(body)+1) == NULL)
@ -511,7 +512,7 @@ parse_configfile(clicon_handle h,
*xconfig = xt;
xt = NULL;
done:
clicon_debug(CLIXON_DBG_DETAIL, "%s: Done w/ config file %s returning %d", __FUNCTION__, filename, retval);
clixon_debug(CLIXON_DBG_DETAIL, "%s: Done w/ config file %s returning %d", __FUNCTION__, filename, retval);
if (dp)
free(dp);
if (nsc)
@ -529,7 +530,7 @@ parse_configfile(clicon_handle h,
*
* Add to clicon_options hash, and to clicon_conf_xml tree
* Assumes clicon_conf_xml_set has been called
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] name Name of configuration option (see clixon-config.yang)
* @param[in] value String value
* @retval 0 OK
@ -559,7 +560,7 @@ clicon_option_add(clicon_handle h,
}
else{
/* Add/change hash */
if (clicon_hash_add(copt,
if (clicon_hash_add(copt,
name,
value,
strlen(value)+1) == NULL)
@ -582,8 +583,10 @@ clicon_option_add(clicon_handle h,
* Set default options, Read config-file, Check that all values are set.
* Parse clixon yang file and save in yspec.
* Read clixon system config files
* @param[in] h clicon handle
* @param[in] yspec Yang spec of clixon config file
* @param[in] h clicon handle
* @param[in] yspec Yang spec of clixon config file
* @retval 0 OK
* @retval -1 Error
* @note Due to Bug: Top-level Yang symbol cannot be called "config" in any
* imported yang file, the config module needs to be isolated from all
* other yang modules.
@ -607,13 +610,13 @@ clicon_options_main(clicon_handle h)
/*
* Set configure file if not set by command-line above
*/
if (!clicon_hash_lookup(copt, "CLICON_CONFIGFILE")){
if (!clicon_hash_lookup(copt, "CLICON_CONFIGFILE")){
clicon_option_str_set(h, "CLICON_CONFIGFILE", CLIXON_DEFAULT_CONFIG);
}
configfile = clicon_hash_value(copt, "CLICON_CONFIGFILE", NULL);
if (strlen(configfile) == 0)
configfile = clicon_hash_value(copt, "CLICON_CONFIGFILE", NULL);
clicon_debug(1, "CLICON_CONFIGFILE=%s", configfile);
clixon_debug(CLIXON_DBG_DEFAULT, "CLICON_CONFIGFILE=%s", configfile);
/* File must end with .xml */
if ((suffix = rindex(configfile, '.')) != NULL){
suffix++;
@ -623,7 +626,6 @@ clicon_options_main(clicon_handle h)
clicon_err(OE_CFG, 0, "%s: suffix %s not recognized", configfile, suffix);
goto done;
}
/* Override extraconfdir */
if (clicon_option_str(h, "CLICON_CONFIGDIR") &&
(extraconfdir = strdup(clicon_option_str(h, "CLICON_CONFIGDIR"))) == NULL){
@ -641,7 +643,6 @@ clicon_options_main(clicon_handle h)
*/
if (parse_configfile(h, configfile, extraconfdir, NULL, &xconfig) < 0)
goto done;
clicon_conf_xml_set(h, xconfig);
#ifdef WITH_RESTCONF_FCGI
@ -660,7 +661,7 @@ clicon_options_main(clicon_handle h)
if (clicon_option_str(h, "CLICON_CONFIG_EXTEND") != NULL)
yangspec = clicon_option_str(h, "CLICON_CONFIG_EXTEND");
if (yang_spec_parse_module(h, yangspec, NULL, yspec) < 0)
goto done;
goto done;
clicon_conf_xml_set(h, NULL);
if (xconfig){
xml_free(xconfig);
@ -718,7 +719,7 @@ clicon_option_exists(clicon_handle h,
* clicon_option_exists() before the call
*/
char *
clicon_option_str(clicon_handle h,
clicon_option_str(clicon_handle h,
const char *name)
{
clicon_hash_t *copt = clicon_options(h);
@ -737,8 +738,8 @@ clicon_option_str(clicon_handle h,
* @retval -1 Error
*/
int
clicon_option_str_set(clicon_handle h,
const char *name,
clicon_option_str_set(clicon_handle h,
const char *name,
char *val)
{
clicon_hash_t *copt = clicon_options(h);
@ -751,7 +752,7 @@ clicon_option_str_set(clicon_handle h,
* @param[in] h clicon handle
* @param[in] name name of option
* @retval int An integer as a result of atoi
* @retval -1 If option does not exist
* @retval -1 If option does not exist
* @code
* if (clicon_option_exists(h, "X"))
* return clicon_option_int(h, "X");
@ -776,7 +777,7 @@ clicon_option_int(clicon_handle h,
/*! Set option given as int.
*
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] name Name of option to set
* @param[in] val Integer value
*/
@ -786,7 +787,7 @@ clicon_option_int_set(clicon_handle h,
int val)
{
char s[64];
if (snprintf(s, sizeof(s)-1, "%u", val) < 0)
return -1;
return clicon_option_str_set(h, name, s);
@ -794,10 +795,10 @@ clicon_option_int_set(clicon_handle h,
/*! Get options as bool but stored as string
*
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] name name of option
* @retval 0 false, or does not exist, or does not have a boolean value
* @retval 1 true
* @retval 0 false, or does not exist, or does not have a boolean value
* @code
* if (clicon_option_exists(h, "X")
* return clicon_option_bool(h, "X");
@ -825,7 +826,7 @@ clicon_option_bool(clicon_handle h,
/*! Set option given as bool
*
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] name Name of option to set
* @param[in] val Boolean value, 0 or 1
*/
@ -835,7 +836,7 @@ clicon_option_bool_set(clicon_handle h,
int val)
{
char s[64];
if (val != 0 && val != 1){
clicon_err(OE_CFG, EINVAL, "val is %d, 0 or 1 expected", val);
return -1;
@ -849,7 +850,7 @@ clicon_option_bool_set(clicon_handle h,
/*! Delete option
*
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] name Name of option to delete
*/
int
@ -874,7 +875,7 @@ clicon_option_del(clicon_handle h,
/*! Get "do not include keys in cvec" in cli vars callbacks
*
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @retval flag If set, get only vars
* @see clixon-config@<date>.yang CLICON_CLI_VARONLY
*/
@ -892,7 +893,7 @@ clicon_cli_varonly(clicon_handle h)
/*! Get family of backend socket: AF_UNIX, AF_INET or AF_INET6
*
* @see clixon-config@<date>.yang CLICON_SOCK_FAMILY
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @retval fam Socket family
*/
int
@ -914,7 +915,7 @@ clicon_sock_family(clicon_handle h)
/*! Get port for backend socket in case of AF_INET or AF_INET6
*
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @retval port Socket port
* @see clixon-config@<date>.yang CLICON_SOCK_PORT
*/
@ -930,7 +931,7 @@ clicon_sock_port(clicon_handle h)
/*! Set if all configuration changes are committed automatically
*
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @retval flag Autocommit (or not)
*/
int
@ -946,7 +947,7 @@ clicon_autocommit(clicon_handle h)
/*! Which method to boot/start clicon backend
*
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @retval mode Startup mode
*/
int
@ -961,7 +962,7 @@ clicon_startup_mode(clicon_handle h)
/*! Which privileges drop method to use for backend
*
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @retval mode Privileges mode
*/
enum priv_mode_t
@ -976,7 +977,7 @@ clicon_backend_privileges_mode(clicon_handle h)
/*! Which privileges drop method to use for restconf
*
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @retval mode Privileges mode
*/
enum priv_mode_t
@ -991,7 +992,7 @@ clicon_restconf_privileges_mode(clicon_handle h)
/*! Which privileges drop method to use
*
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @retval mode Privileges mode
*/
enum nacm_credentials_t
@ -1006,7 +1007,7 @@ clicon_nacm_credentials(clicon_handle h)
/*! Which datastore cache method to use
*
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @retval method Datastore cache method
* @see clixon-config@<date>.yang CLICON_DATASTORE_CACHE
*/
@ -1023,7 +1024,7 @@ clicon_datastore_cache(clicon_handle h)
/*! Which Yang regexp/pattern engine to use
*
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @retval mode Regexp engine to use
* @see clixon-config@<date>.yang CLICON_YANG_REGEXP
*/
@ -1046,7 +1047,7 @@ clicon_yang_regexp(clicon_handle h)
/*! Get quiet mode eg -q option, do not print notifications on stdout
*
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @retval flag quiet mode on or off
*/
int
@ -1060,7 +1061,7 @@ clicon_quiet_mode(clicon_handle h)
/*! Set quiet mode
*
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] val Flag value
*/
int

View file

@ -91,7 +91,7 @@
#include "clixon_err.h"
#include "clixon_log.h"
#include "clixon_options.h"
#include "clixon_yang.h"
#include "clixon_yang.h"
#include "clixon_xml.h"
#include "clixon_xml_nsctx.h"
#include "clixon_xml_vec.h"
@ -131,7 +131,7 @@ api_path_parse(char *api_path,
int retval = -1;
clixon_api_path_yacc ay = {0,};
clicon_debug(1, "%s api_path:%s", __FUNCTION__, api_path);
clixon_debug(CLIXON_DBG_DEFAULT, "%s api_path:%s", __FUNCTION__, api_path);
ay.ay_parse_string = api_path;
ay.ay_name = "api-path parser";
ay.ay_linenum = 1;
@ -176,7 +176,7 @@ instance_id_parse(char *path,
int retval = -1;
clixon_instance_id_yacc iy = {0,};
clicon_debug(1, "%s path:%s", __FUNCTION__, path);
clixon_debug(CLIXON_DBG_DEFAULT, "%s path:%s", __FUNCTION__, path);
iy.iy_parse_string = path;
iy.iy_name = "instance-id parser";
iy.iy_linenum = 1;
@ -202,7 +202,7 @@ int
clixon_path_free(clixon_path *cplist)
{
clixon_path *cp;
while ((cp = cplist) != NULL){
DELQ(cp, cplist, clixon_path *);
if (cp->cp_prefix)
@ -224,7 +224,7 @@ clixon_path_print(FILE *f,
{
clixon_path *cp;
cg_var *cv;
if ((cp = cplist) != NULL){
do {
fprintf(f, "/");
@ -244,7 +244,7 @@ clixon_path_print(FILE *f,
fprintf(f, "]");
}
}
cp = NEXTQ(clixon_path *, cp);
cp = NEXTQ(clixon_path *, cp);
} while (cp && cp != cplist);
}
fprintf(f, "\n");
@ -252,21 +252,22 @@ clixon_path_print(FILE *f,
}
/*! Given an XML node, return root node
*
* A root node is an ancestor xr of x with one or both of the following properties
* - its XML parent is NULL parent,
* - its associated yang specification's parent is a yang module.
* @param[in] x XML node
* @param[out] xr XML root
* @retval 0 OK
*/
int
xml_yang_root(cxobj *x,
cxobj **xr)
{
int retval = -1;
cxobj *xp;
yang_stmt *y;
yang_stmt *yp;
while ((xp = xml_parent(x)) != NULL){
if ((y = xml_spec(x)) != NULL &&
(yp = yang_parent_get(y)) != NULL)
@ -278,11 +279,11 @@ xml_yang_root(cxobj *x,
x = xp;
}
*xr = x;
retval = 0;
return retval;
return 0;
}
/*! Construct an api-path key format from yang statement using wildcards for keys
*
* Recursively construct it to the top.
* Example:
* yang: container a -> list b -> key c -> leaf d
@ -293,9 +294,9 @@ xml_yang_root(cxobj *x,
* @retval 0 OK
* @retval -1 Error
* @see RFC8040 3.5.3 where "api-path" is defined as "URI-encoded path expression"
*/
*/
static int
yang2api_path_fmt_1(yang_stmt *ys,
yang2api_path_fmt_1(yang_stmt *ys,
int inclkey,
cbuf *cb)
{
@ -306,7 +307,7 @@ yang2api_path_fmt_1(yang_stmt *ys,
cvec *cvk = NULL; /* vector of index keys */
int retval = -1;
enum rfc_6020 ypkeyw = -1;
if ((yp = yang_parent_get(ys)) == NULL){
clicon_err(OE_YANG, EINVAL, "yang expected parent %s", yang_argument_get(ys));
goto done;
@ -331,9 +332,9 @@ yang2api_path_fmt_1(yang_stmt *ys,
* But in other cases (I think most), the / should be there,
* so a patch is added in cli_show_auto instead.
*/
if (yang_keyword_get(ys) == Y_LEAF && yp &&
ypkeyw == Y_LIST &&
yang_key_match(yp, ys->ys_argument, NULL) == 1)
if (yang_keyword_get(ys) == Y_LEAF && yp &&
ypkeyw == Y_LIST &&
yang_key_match(yp, ys->ys_argument, NULL) == 1)
;
else
#endif
@ -353,12 +354,12 @@ yang2api_path_fmt_1(yang_stmt *ys,
cprintf(cb, "%s", yang_argument_get(ys));
}
else{
if (yang_keyword_get(ys) == Y_LEAF && yp &&
if (yang_keyword_get(ys) == Y_LEAF && yp &&
ypkeyw == Y_LIST){
if (yang_key_match(yp, yang_argument_get(ys), NULL) == 0)
cprintf(cb, "%s", yang_argument_get(ys)); /* Not if leaf and key */
}
else
else
if (yang_keyword_get(ys) != Y_CHOICE && yang_keyword_get(ys) != Y_CASE)
cprintf(cb, "%s", yang_argument_get(ys));
}
@ -398,9 +399,9 @@ yang2api_path_fmt_1(yang_stmt *ys,
* @retval 0 OK
* @retval -1 Error
* "api-path" is "URI-encoded path expression" definition in RFC8040 3.5.3
*/
*/
int
yang2api_path_fmt(yang_stmt *ys,
yang2api_path_fmt(yang_stmt *ys,
int inclkey,
char **api_path_fmt)
{
@ -425,6 +426,7 @@ yang2api_path_fmt(yang_stmt *ys,
}
/*! Transform an xml key format and a vector of values to an XML key
*
* Used for actual key, eg in clicon_rpc_change(), xmldb_put_xkey()
* Example:
* xmlkeyfmt: /interfaces/interface=%s/ipv4/address=%s
@ -438,7 +440,7 @@ yang2api_path_fmt(yang_stmt *ys,
* @param[out] cvv_i 1..cvv-len. Index into cvv of last cvv entry used, For example,
* if same as len of cvv, all were used, if < some entries were not
* @retval 0 OK
* @retval -1 Error
* @retval -1 Error
* @note first and last elements of cvv are not used,..
* @see api_path_fmt2xpath
* @example
@ -457,8 +459,8 @@ yang2api_path_fmt(yang_stmt *ys,
* "api-path" is "URI-encoded path expression" definition in RFC8040 3.5.3
*/
int
api_path_fmt2api_path(const char *api_path_fmt,
cvec *cvv,
api_path_fmt2api_path(const char *api_path_fmt,
cvec *cvv,
char **api_path,
int *cvv_i)
{
@ -472,7 +474,7 @@ api_path_fmt2api_path(const char *api_path_fmt,
char *strenc=NULL;
cg_var *cv;
size_t len;
if ((cb = cbuf_new()) == NULL){
clicon_err(OE_UNIX, errno, "cbuf_new");
goto done;
@ -498,7 +500,7 @@ api_path_fmt2api_path(const char *api_path_fmt,
}
if (uri_percent_encode(&strenc, "%s", str) < 0)
goto done;
cprintf(cb, "%s", strenc);
cprintf(cb, "%s", strenc);
free(strenc); strenc = NULL;
free(str); str = NULL;
}
@ -518,7 +520,7 @@ api_path_fmt2api_path(const char *api_path_fmt,
goto done;
}
if (cvv_i) /* Last entry in cvv used */
*cvv_i = j;
*cvv_i = j;
retval = 0;
done:
if (cb)
@ -527,10 +529,13 @@ api_path_fmt2api_path(const char *api_path_fmt,
}
/*! Transform an xml key format and a vector of values to an XML path
*
* Used to input xmldb_get()
* @param[in] api_path_fmt XML key format
* @param[in] cvv cligen variable vector, one for every wildchar in api_path_fmt
* @param[out] xpath XPATH
* @param[in] cvv cligen variable vector, one for every wildchar in api_path_fmt
* @param[out] xpath XPath
* @retval 0 OK
* @retval -1 Error
* Add .* in last %s position.
* @example
* api_path_fmt: /interface/%s/address/%s
@ -548,10 +553,10 @@ api_path_fmt2api_path(const char *api_path_fmt,
* api_path_fmt: /a:b/c
* xpath : /b/c prefix:a
* "api-path" is "URI-encoded path expression" definition in RFC8040 3.5.3
*/
*/
int
api_path_fmt2xpath(char *api_path_fmt,
cvec *cvv,
api_path_fmt2xpath(char *api_path_fmt,
cvec *cvv,
char **xpath)
{
int retval = -1;
@ -675,7 +680,7 @@ api_path2xpath_cvv(cvec *api_path,
char *decval;
int ret;
int root;
cprintf(xpath, "/");
/* Initialize namespace context */
if ((nsc = xml_nsctx_init(NULL, NULL)) == NULL)
@ -691,7 +696,7 @@ api_path2xpath_cvv(cvec *api_path,
/* api-path: prefix points to module */
if (nodeid_split(nodeid, &prefix, &name) < 0)
goto done;
clicon_debug(CLIXON_DBG_DETAIL, "%s [%d] cvname: %s:%s",
clixon_debug(CLIXON_DBG_DETAIL, "%s [%d] cvname: %s:%s",
__FUNCTION__, i, prefix?prefix:"", name);
/* top-node must have prefix */
if (i == offset && prefix == NULL){
@ -725,8 +730,8 @@ api_path2xpath_cvv(cvec *api_path,
*/
if (xml_nsctx_get_prefix(nsc, namespace, &xprefix) == 0){
xprefix = yang_find_myprefix(y);
clicon_debug(CLIXON_DBG_DETAIL, "%s prefix not found add it %s", __FUNCTION__, xprefix);
/* not found, add it to nsc
clixon_debug(CLIXON_DBG_DETAIL, "%s prefix not found add it %s", __FUNCTION__, xprefix);
/* not found, add it to nsc
* XXX: do we always have to add it? It could be default?
*/
// if (xml2prefix(x1, namespace, &pexisting));
@ -809,7 +814,7 @@ api_path2xpath_cvv(cvec *api_path,
if (ret == 1){
yang_stmt *y1 = NULL;
if (xml_nsctx_yangspec(yspec, &nsc) < 0)
goto done;
goto done;
if (yang_mount_get(y, cbuf_get(xpath), &y1) < 0)
goto done;
if (y1 == NULL || yang_keyword_get(y1) != Y_SPEC){
@ -834,7 +839,7 @@ api_path2xpath_cvv(cvec *api_path,
nsc = NULL;
}
done:
clicon_debug(CLIXON_DBG_DETAIL, "%s retval:%d", __FUNCTION__, retval);
clixon_debug(CLIXON_DBG_DETAIL, "%s retval:%d", __FUNCTION__, retval);
if (cberr)
cbuf_free(cberr);
if (valvec)
@ -852,6 +857,7 @@ api_path2xpath_cvv(cvec *api_path,
}
/*! Translate from restconf api-path to xml xpath and namespace
*
* @param[in] api_path URI-encoded path expression" (RFC8040 3.5.3)
* @param[in] yspec Yang spec
* @param[out] xpath xpath (use free() to deallocate)
@ -1049,7 +1055,7 @@ api_path2xml_vec(char **vec,
goto done;
xml_spec_set(x, y);
if ((xb = xml_new("body", x, CX_BODY)) == NULL)
goto done;
goto done;
if (restval){
if (uri_percent_decode(restval, &val) < 0)
goto done;
@ -1075,7 +1081,7 @@ api_path2xml_vec(char **vec,
*/
if ((valvec = clicon_strsep(restval, ",", &nvalvec)) == NULL)
goto done;
if ((nvalvec != cvec_len(cvk)) && strict){
if ((nvalvec != cvec_len(cvk)) && strict){
cprintf(cberr, "List key %s length mismatch", name);
if (xerr &&
netconf_malformed_message_xml(xerr, cbuf_get(cberr)) < 0)
@ -1104,7 +1110,7 @@ api_path2xml_vec(char **vec,
}
if (x != NULL){
if ((xn = xml_new(keyname, x, CX_ELMNT)) == NULL)
goto done;
goto done;
xml_spec_set(xn, ykey);
if ((xb = xml_new("body", xn, CX_BODY)) == NULL)
goto done;
@ -1151,7 +1157,7 @@ api_path2xml_vec(char **vec,
if (ret == 1){
yang_stmt *y1 = NULL;
if (xml_nsctx_yangspec(ys_spec(y), &nsc) < 0)
goto done;
goto done;
if (xml2xpath(x, nsc, 0, 1, &xpath) < 0) // XXX should be canonical
goto done;
if (xpath == NULL){
@ -1166,15 +1172,15 @@ api_path2xml_vec(char **vec,
}
y = y1;
}
if ((retval = api_path2xml_vec(vec+1, nvec-1,
x, y,
nodeclass, strict,
if ((retval = api_path2xml_vec(vec+1, nvec-1,
x, y,
nodeclass, strict,
xbotp, ybotp, xerr)) < 1)
goto done;
ok:
retval = 1; /* OK */
done:
clicon_debug(CLIXON_DBG_DETAIL, "%s retval:%d", __FUNCTION__, retval);
clixon_debug(CLIXON_DBG_DETAIL, "%s retval:%d", __FUNCTION__, retval);
if (xpath)
free(xpath);
if (nsc)
@ -1243,7 +1249,7 @@ api_path2xml(char *api_path,
cxobj *xroot;
cbuf *cberr = NULL;
clicon_debug(CLIXON_DBG_DETAIL, "%s api_path:%s", __FUNCTION__, api_path);
clixon_debug(CLIXON_DBG_DETAIL, "%s api_path:%s", __FUNCTION__, api_path);
if ((cberr = cbuf_new()) == NULL){
clicon_err(OE_UNIX, errno, "cbuf_new");
goto done;
@ -1267,7 +1273,7 @@ api_path2xml(char *api_path,
}
nvec--; /* NULL-terminated */
if ((retval = api_path2xml_vec(vec+1, nvec,
xtop, yspec, nodeclass, strict,
xtop, yspec, nodeclass, strict,
xbotp, ybotp, xerr)) < 1)
goto done;
/* Fix namespace */
@ -1289,6 +1295,7 @@ api_path2xml(char *api_path,
}
/*! Construct an api_path from an XML node (single level not recursive)
*
* @param[in] x XML node (need to be yang populated)
* @param[out] cb api_path, must be initialized
* @retval 0 OK
@ -1313,7 +1320,7 @@ xml2api_path_1(cxobj *x,
char *enc;
yang_stmt *ymod;
cxobj *xp;
if ((y = xml_spec(x)) == NULL){
cprintf(cb, "/%s", xml_name(x));
goto ok;
@ -1377,11 +1384,12 @@ xml2api_path_1(cxobj *x,
}
/*! Resolve api-path module:names to yang statements
*
* @param[in] cplist Lisp of clixon-path
* @param[in] yt Yang statement of top symbol (can be yang-spec if top-level)
* @retval -1 Error
* @retval 0 Fail
* @retval 1 OK
* @retval 0 Fail
* @retval -1 Error
* Reasons for fail (retval = 0) are: XXX
* - Modulename in api-path does not correspond to existing module
* - Modulename not defined for top-level id.
@ -1401,7 +1409,7 @@ api_path_resolve(clixon_path *cplist,
cg_var *cva;
cg_var *cvy;
cvec *cvk;
if ((cp = cplist) != NULL){
do {
if (yang_keyword_get(yt) == Y_SPEC){
@ -1464,11 +1472,12 @@ api_path_resolve(clixon_path *cplist,
}
/*! Resolve instance-id prefix:names to yang statements
*
* @param[in] cplist Lisp of clixon-path
* @param[in] yt Yang statement of top symbol (can be yang-spec if top-level)
* @retval -1 Error
* @retval 0 Fail error in xerr
* @retval 1 OK
* @retval 0 Fail error in xerr
* @retval -1 Error
* @note: The spec says: prefixes depend on the XML context in which the value occurs.
* However, canonical prefixes/namespaces are used based on loaded yang modules.
* This means that prefix=NULL is not allowed.
@ -1492,7 +1501,7 @@ instance_id_resolve(clixon_path *cplist,
cg_var *cva;
yang_stmt *yspec;
char *kname;
yspec = ys_spec(yt);
if ((cp = cplist) != NULL){
do {
@ -1517,7 +1526,7 @@ instance_id_resolve(clixon_path *cplist,
if (cp->cp_cvk == NULL){
#if 0 /* see key-value presence in lists note above */
clicon_err(OE_YANG, ENOENT, "key-values mandatory for lists");
goto fail;
goto fail;
#endif
break;
}
@ -1537,7 +1546,6 @@ instance_id_resolve(clixon_path *cplist,
}
}
else{ /* Assume index */
}
}
break;
@ -1568,9 +1576,9 @@ instance_id_resolve(clixon_path *cplist,
* @param[in] yt Yang statement of top symbol (can be yang-spec if top-level)
* @param[in] cplist Lisp of clixon-path
* @param[out] xvec Vector of xml-trees. Vector must be free():d after use
* @retval -1 Error
* @retval 0 Fail fail: eg no yang
* @retval 1 OK with found xml nodes in xvec (if any)
* @retval 0 Fail fail: eg no yang
* @retval -1 Error
*/
static int
clixon_path_search(cxobj *xt,
@ -1584,12 +1592,12 @@ clixon_path_search(cxobj *xt,
clixon_xvec *xvecp = NULL;
clixon_xvec *xvecc = NULL;
yang_stmt *yc;
cxobj *xp;
cxobj *xp;
int i;
cg_var *cv;
if ((xvecp = clixon_xvec_new()) == NULL)
goto done;
goto done;
modns = NULL;
if ((cp = cplist) != NULL){
if (clixon_xvec_append(xvecp, xt) < 0)
@ -1645,9 +1653,9 @@ clixon_path_search(cxobj *xt,
* @param[in] yt Yang statement of top symbol (can be yang-spec if top-level)
* @param[out] xvec Vector of xml-trees. Vector must be free():d after use
* @param[in] format Format string for api-path syntax
* @retval -1 Error
* @retval 0 Non-fatal failure, yang bind failures, etc,
* @retval 1 OK with found xml nodes in xvec (if any) (xvec contains matches)
* @retval 0 Non-fatal failure, yang bind failures, etc,
* @retval -1 Error
* Reasons for nomatch (retval = 0) are:
* - Modulename in api-path does not correspond to existing module
* - Modulename not defined for top-level id.
@ -1666,7 +1674,7 @@ clixon_path_search(cxobj *xt,
* @see clixon_xml_find_instance_id
*/
int
clixon_xml_find_api_path(cxobj *xt,
clixon_xml_find_api_path(cxobj *xt,
yang_stmt *yt,
cxobj ***xvec,
int *xlen,
@ -1680,7 +1688,7 @@ clixon_xml_find_api_path(cxobj *xt,
clixon_path *cplist = NULL;
int ret;
clixon_xvec *xv = NULL;
va_start(ap, format);
len = vsnprintf(NULL, 0, format, ap);
va_end(ap);
@ -1700,7 +1708,7 @@ clixon_xml_find_api_path(cxobj *xt,
/* Parse api-path string to structured clixon-path data */
if (api_path_parse(api_path, &cplist) < 0)
goto done;
if (clicon_debug_get())
if (clixon_debug_get())
clixon_path_print(stderr, cplist);
/* Resolve module:name to yang-stmt, fail if not successful */
if ((ret = api_path_resolve(cplist, yt)) < 0)
@ -1737,9 +1745,9 @@ clixon_xml_find_api_path(cxobj *xt,
* @param[out] xvec Vector of xml-trees. Vector must be free():d after use
* @param[out] xlen Returns length of vector in return value
* @param[in] format Format string for api-path syntax
* @retval -1 Error
* @retval 0 Non-fatal failure, yang bind failures, etc,
* @retval 1 OK with found xml nodes in xvec (if any)
* @retval 0 Non-fatal failure, yang bind failures, etc,
* @retval -1 Error
* Reasons for nomatch (retval = 0) are:
* - Modulename in api-path does not correspond to existing module
* - Modulename not defined for top-level id.
@ -1760,7 +1768,7 @@ clixon_xml_find_api_path(cxobj *xt,
* @see RFC7950 Sec 9.13
*/
int
clixon_xml_find_instance_id(cxobj *xt,
clixon_xml_find_instance_id(cxobj *xt,
yang_stmt *yt,
cxobj ***xvec,
int *xlen,
@ -1774,7 +1782,7 @@ clixon_xml_find_instance_id(cxobj *xt,
clixon_path *cplist = NULL;
int ret;
clixon_xvec *xv = NULL;
va_start(ap, format);
len = vsnprintf(NULL, 0, format, ap);
va_end(ap);
@ -1793,7 +1801,7 @@ clixon_xml_find_instance_id(cxobj *xt,
va_end(ap);
if (instance_id_parse(path, &cplist) < 0)
goto done;
if (clicon_debug_get())
if (clixon_debug_get())
clixon_path_print(stderr, cplist);
/* Resolve module:name to pointer to yang-stmt, fail if not successful */
if ((ret = instance_id_resolve(cplist, yt)) < 0)
@ -1828,9 +1836,9 @@ clixon_xml_find_instance_id(cxobj *xt,
* @param[in] yt Yang statement of top symbol (can be yang-spec if top-level)
* @param[out] nsctx Namespace context (should be created on entry)
* @param[in] format Format string for xpath syntax
* @retval -1 Error
* @retval 0 Non-fatal failure, yang bind failures, etc,
* @retval 1 OK with found xml nodes in xvec (if any)
* @retval 0 Non-fatal failure, yang bind failures, etc,
* @retval -1 Error
* Reasons for nomatch (retval = 0) are:
* - Modulename in api-path does not correspond to existing module
* - Modulename not defined for top-level id.
@ -1862,7 +1870,7 @@ clixon_instance_id_bind(yang_stmt *yt,
clixon_path *cp;
int ret;
char *namespace;
va_start(ap, format);
len = vsnprintf(NULL, 0, format, ap);
va_end(ap);
@ -1881,7 +1889,7 @@ clixon_instance_id_bind(yang_stmt *yt,
va_end(ap);
if (instance_id_parse(path, &cplist) < 0)
goto done;
if (clicon_debug_get())
if (clixon_debug_get())
clixon_path_print(stderr, cplist);
/* Resolve module:name to pointer to yang-stmt, fail if not successful */
if ((ret = instance_id_resolve(cplist, yt)) < 0)
@ -1921,9 +1929,9 @@ clixon_instance_id_bind(yang_stmt *yt,
* @param[out] cplistp Path parse-tree
* @param[out] xerr Contains error if retval=0
* @param[in] format Format string for xpath syntax
* @retval -1 Error
* @retval 0 Non-fatal failure, yang bind failures, etc,
* @retval 1 OK with found xml nodes in xvec (if any)
* @retval 0 Non-fatal failure, yang bind failures, etc,
* @retval -1 Error
*/
int
clixon_instance_id_parse(yang_stmt *yt,
@ -1938,7 +1946,7 @@ clixon_instance_id_parse(yang_stmt *yt,
char *path = NULL;
clixon_path *cplist = NULL;
int ret;
va_start(ap, format);
len = vsnprintf(NULL, 0, format, ap);
va_end(ap);
@ -1957,7 +1965,7 @@ clixon_instance_id_parse(yang_stmt *yt,
va_end(ap);
if (instance_id_parse(path, &cplist) < 0)
goto done;
if (clicon_debug_get())
if (clixon_debug_get())
clixon_path_print(stderr, cplist);
/* Resolve module:name to pointer to yang-stmt, fail if not successful */
if ((ret = instance_id_resolve(cplist, yt)) < 0)

View file

@ -76,6 +76,7 @@
* Private types
*/
/*! Structure for checking status before and after a plugin call
*
* Currently signal settings: blocked and handlers, and termios
* @see plugin_context_check
*/
@ -121,7 +122,8 @@ struct plugin_module_struct {
typedef struct plugin_module_struct plugin_module_struct;
/*! Get plugin handle containing plugin and callback lists
* @param[in] h Clicon handle
*
* @param[in] h Clixon handle
*/
static plugin_module_struct *
plugin_module_struct_get(clicon_handle h)
@ -136,8 +138,11 @@ plugin_module_struct_get(clicon_handle h)
}
/*! Set plugin handle containing plugin and callback lists
* @param[in] h Clicon handle
*
* @param[in] h Clixon handle
* @param[in] pl Clixon plugin handle
* @retval 0 OK
* @retval -1 Error
*/
static int
plugin_module_struct_set(clicon_handle h,
@ -156,8 +161,9 @@ plugin_module_struct_set(clicon_handle h,
/* Access functions */
/*! Get plugin api
*
* @param[in] cp Clixon plugin handle
*/
*/
clixon_plugin_api *
clixon_plugin_api_get(clixon_plugin_t *cp)
{
@ -165,8 +171,9 @@ clixon_plugin_api_get(clixon_plugin_t *cp)
}
/*! Get plugin name
*
* @param[in] cp Clixon plugin handle
*/
*/
char *
clixon_plugin_name_get(clixon_plugin_t *cp)
{
@ -174,8 +181,9 @@ clixon_plugin_name_get(clixon_plugin_t *cp)
}
/*! Get plugin handle
*
* @param[in] cp Clixon plugin handle
*/
*/
plghndl_t
clixon_plugin_handle_get(clixon_plugin_t *cp)
{
@ -187,7 +195,7 @@ clixon_plugin_handle_get(clixon_plugin_t *cp)
* @note Never manipulate the plugin during operation or using the
* same object recursively
*
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] plugin previous plugin, or NULL on init
* @code
* clicon_plugin *cp = NULL;
@ -201,7 +209,7 @@ clixon_plugin_t *
clixon_plugin_each(clicon_handle h,
clixon_plugin_t *cpprev)
{
clixon_plugin_t *cpnext = NULL;
clixon_plugin_t *cpnext = NULL;
plugin_module_struct *ms = plugin_module_struct_get(h);
/* ms == NULL means plugins are not yet initialized */
@ -222,7 +230,7 @@ clixon_plugin_each(clicon_handle h,
* @note Never manipulate the plugin during operation or using the
* same object recursively
*
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] plugin previous plugin, or NULL on init
* @param[in] nr Start from this nr <= lngth of list
* @code
@ -238,9 +246,9 @@ clixon_plugin_each_revert(clicon_handle h,
clixon_plugin_t *cpprev,
int nr)
{
int i;
clixon_plugin_t *cpnext = NULL;
clixon_plugin_t *cpnext = NULL;
plugin_module_struct *ms = plugin_module_struct_get(h);
int i;
if (ms == NULL){
clicon_err(OE_PLUGIN, EINVAL, "plugin module not initialized");
@ -263,12 +271,13 @@ clixon_plugin_each_revert(clicon_handle h,
cpnext = NULL;
else
cpnext = PREVQ(clixon_plugin_t *, cpprev);
}
}
return cpnext;
}
/*! Find plugin by name
* @param[in] h Clicon handle
*
* @param[in] h Clixon handle
* @param[in] name Plugin name
* @retval p Plugin if found
* @retval NULL Not found
@ -300,7 +309,7 @@ clixon_plugin_find(clicon_handle h,
/*! Load a dynamic plugin object and call its init-function
*
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] file Which plugin to load
* @param[in] function Which function symbol to load and call
* @param[in] dlflags See man(3) dlopen
@ -311,7 +320,7 @@ clixon_plugin_find(clicon_handle h,
* @see clixon_plugins_load Load all plugins
*/
static int
plugin_load_one(clicon_handle h,
plugin_load_one(clicon_handle h,
char *file, /* note modified */
const char *function,
int dlflags,
@ -327,7 +336,7 @@ plugin_load_one(clicon_handle h,
char *p;
void *wh = NULL;
clicon_debug(1, "%s file:%s function:%s", __FUNCTION__, file, function);
clixon_debug(CLIXON_DBG_DEFAULT, "%s file:%s function:%s", __FUNCTION__, file, function);
dlerror(); /* Clear any existing error */
if ((handle = dlopen(file, dlflags)) == NULL) {
error = (char*)dlerror();
@ -382,7 +391,7 @@ plugin_load_one(clicon_handle h,
}
retval = 1;
done:
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
clixon_debug(CLIXON_DBG_DEFAULT, "%s retval:%d", __FUNCTION__, retval);
if (wh != NULL)
free(wh);
if (retval != 1 && handle)
@ -393,12 +402,13 @@ plugin_load_one(clicon_handle h,
}
/*! Load a set of plugin objects from a directory and and call their init-function
* @param[in] h Clicon handle
*
* @param[in] h Clixon handle
* @param[in] function Which function symbol to load and call (eg CLIXON_PLUGIN_INIT)
* @param[in] dir Directory. .so files in this dir will be loaded.
* @param[in] regexp Regexp for matching files in plugin directory. Default *.so.
* @retval 0 OK
* @retval -1 Error
* @retval -1 Error
*/
int
clixon_plugins_load(clicon_handle h,
@ -415,8 +425,8 @@ clixon_plugins_load(clicon_handle h,
int ret;
plugin_module_struct *ms = plugin_module_struct_get(h);
int dlflags;
clicon_debug(CLIXON_DBG_DETAIL, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DETAIL, "%s", __FUNCTION__);
if (ms == NULL){
clicon_err(OE_PLUGIN, EINVAL, "plugin module not initialized");
goto done;
@ -427,7 +437,7 @@ clixon_plugins_load(clicon_handle h,
/* Load all plugins */
for (i = 0; i < ndp; i++) {
snprintf(filename, MAXPATHLEN-1, "%s/%s", dir, dp[i].d_name);
clicon_debug(CLIXON_DBG_DEFAULT, "Loading plugin '%s'", filename);
clixon_debug(CLIXON_DBG_DEFAULT, "Loading plugin '%s'", filename);
dlflags = RTLD_NOW;
if (clicon_option_bool(h, "CLICON_PLUGIN_DLOPEN_GLOBAL"))
dlflags |= RTLD_GLOBAL;
@ -447,7 +457,8 @@ done:
}
/*! Create a pseudo plugin so that a main function can register callbacks
* @param[in] h Clicon handle
*
* @param[in] h Clixon handle
* @param[in] name Plugin name
* @param[out] cpp Clixon plugin structure (direct pointer)
* @retval 0 OK, with cpp set
@ -468,7 +479,7 @@ clixon_pseudo_plugin(clicon_handle h,
clixon_plugin_t *cp = NULL;
plugin_module_struct *ms = plugin_module_struct_get(h);
clicon_debug(1, "%s %s", __FUNCTION__, name);
clixon_debug(CLIXON_DBG_DEFAULT, "%s %s", __FUNCTION__, name);
if (ms == NULL){
clicon_err(OE_PLUGIN, EINVAL, "plugin module not initialized");
goto done;
@ -492,6 +503,7 @@ done:
}
/*! Get system context, eg signal procmask (for blocking) and sigactions
*
* Call this before a plugin
* @retval pc Plugin context structure, use free() to deallocate
* @retval NULL Error
@ -670,6 +682,7 @@ plugin_context_check(clicon_handle h,
}
/*! Call single plugin start callback
*
* @param[in] cp Plugin handle
* @param[in] h Clixon handle
* @retval 0 OK
@ -688,7 +701,7 @@ clixon_plugin_start_one(clixon_plugin_t *cp,
if (plugin_context_check(h, &wh, cp->cp_name, __FUNCTION__) < 0)
goto done;
if (fn(h) < 0) {
if (clicon_errno < 0)
if (clicon_errno < 0)
clicon_log(LOG_WARNING, "%s: Internal error: Start callback in plugin: %s returned -1 but did not make a clicon_err call",
__FUNCTION__, cp->cp_name);
goto done;
@ -702,7 +715,10 @@ clixon_plugin_start_one(clixon_plugin_t *cp,
}
/*! Call plugin_start in all plugins
*
* @param[in] h Clixon handle
* @retval 0 OK
* @retval -1 Error
* Call plugin start functions (if defined)
* @note Start functions can use clicon_argv_get() to get -- command line options
*/
@ -722,7 +738,8 @@ clixon_plugin_start_all(clicon_handle h)
}
/*! Unload all plugins: call exit function and close shared handle
* @param[in] h Clicon handle
*
* @param[in] h Clixon handle
* @param[in] cp Plugin handle
* @param[in] h Clixon handle
* @retval 0 OK
@ -736,13 +753,13 @@ clixon_plugin_exit_one(clixon_plugin_t *cp,
char *error;
plgexit_t *fn;
void *wh = NULL;
if ((fn = cp->cp_api.ca_exit) != NULL){
wh = NULL;
if (plugin_context_check(h, &wh, cp->cp_name, __FUNCTION__) < 0)
goto done;
if (fn(h) < 0) {
if (clicon_errno < 0)
if (clicon_errno < 0)
clicon_log(LOG_WARNING, "%s: Internal error: Exit callback in plugin: %s returned -1 but did not make a clicon_err call",
__FUNCTION__, cp->cp_name);
goto done;
@ -760,6 +777,7 @@ clixon_plugin_exit_one(clixon_plugin_t *cp,
}
/*! Unload all plugins: call exit function and close shared handle
*
* @param[in] h Clixon handle
* @retval 0 OK
* @retval -1 Error
@ -784,8 +802,9 @@ clixon_plugin_exit_all(clicon_handle h)
return retval;
}
/*! Run the restconf user-defined credentials callback
* @param[in] h Clicon handle
/*! Run the restconf user-defined credentials callback
*
* @param[in] h Clixon handle
* @param[in] req Per-message request www handle to use with restconf_api.h
* @param[in] auth_type Authentication type: none, user-defined, or client-cert
* @param[out] authp NULL: Credentials failed, no user set (401 returned).
@ -798,23 +817,23 @@ clixon_plugin_exit_all(clicon_handle h)
* Or no callback was found.
*/
static int
clixon_plugin_auth_one(clixon_plugin_t *cp,
clicon_handle h,
clixon_plugin_auth_one(clixon_plugin_t *cp,
clicon_handle h,
void *req,
clixon_auth_type_t auth_type,
char **authp)
{
int retval = -1;
int retval = -1;
plgauth_t *fn; /* Plugin auth */
void *wh = NULL;
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
if ((fn = cp->cp_api.ca_auth) != NULL){
wh = NULL;
if (plugin_context_check(h, &wh, cp->cp_name, __FUNCTION__) < 0)
goto done;
if ((retval = fn(h, req, auth_type, authp)) < 0) {
if (clicon_errno < 0)
if (clicon_errno < 0)
clicon_log(LOG_WARNING, "%s: Internal error: Auth callback in plugin: %s returned -1 but did not make a clicon_err call",
__FUNCTION__, cp->cp_name);
goto done;
@ -825,14 +844,15 @@ clixon_plugin_auth_one(clixon_plugin_t *cp,
else
retval = 0; /* Ignored / no callback */
done:
clicon_debug(1, "%s retval:%d auth:%s", __FUNCTION__, retval, *authp);
clixon_debug(CLIXON_DBG_DEFAULT, "%s retval:%d auth:%s", __FUNCTION__, retval, *authp);
return retval;
}
/*! Run the restconf user-defined credentials callback for all plugins
*
* Find first authentication callback and call that, then return.
* The callback is to set the authenticated user
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] req Per-message request www handle to use with restconf_api.h
* @param[in] auth_type Authentication type: none, user-defined, or client-cert
* @param[out] authp NULL: Credentials failed, no user set (401 returned).
@ -844,20 +864,20 @@ clixon_plugin_auth_one(clixon_plugin_t *cp,
* @note If authp returns string, it should be malloced
*/
int
clixon_plugin_auth_all(clicon_handle h,
clixon_plugin_auth_all(clicon_handle h,
void *req,
clixon_auth_type_t auth_type,
char **authp)
{
int retval = -1;
clixon_plugin_t *cp = NULL;
int ret = 0;
clicon_debug(1, "%s", __FUNCTION__);
int ret = 0;
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
if (authp == NULL){
clicon_err(OE_PLUGIN, EINVAL, "Authp output parameter is NULL");
goto done;
}
}
*authp = NULL;
ret = 0; /* ignore */
while ((cp = clixon_plugin_each(h, cp)) != NULL) {
@ -869,11 +889,12 @@ clixon_plugin_auth_all(clicon_handle h,
}
retval = ret;
done:
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
clixon_debug(CLIXON_DBG_DEFAULT, "%s retval:%d", __FUNCTION__, retval);
return retval;
}
/*! Callback for a yang extension (unknown) statement single plugin
*
* extension can be made.
* @param[in] cp Plugin handle
* @param[in] h Clixon handle
@ -884,20 +905,20 @@ clixon_plugin_auth_all(clicon_handle h,
*/
int
clixon_plugin_extension_one(clixon_plugin_t *cp,
clicon_handle h,
yang_stmt *yext,
yang_stmt *ys)
clicon_handle h,
yang_stmt *yext,
yang_stmt *ys)
{
int retval = 1;
plgextension_t *fn; /* Plugin extension fn */
void *wh = NULL;
if ((fn = cp->cp_api.ca_extension) != NULL){
wh = NULL;
if (plugin_context_check(h, &wh, cp->cp_name, __FUNCTION__) < 0)
goto done;
if (fn(h, yext, ys) < 0) {
if (clicon_errno < 0)
if (clicon_errno < 0)
clicon_log(LOG_WARNING, "%s: Internal error: Extension callback in plugin: %s returned -1 but did not make a clicon_err call",
__FUNCTION__, cp->cp_name);
goto done;
@ -911,6 +932,7 @@ clixon_plugin_extension_one(clixon_plugin_t *cp,
}
/*! Callback for a yang extension (unknown) statement in all plugins
*
* Called at parsing of yang module containing a statement of an extension.
* A plugin may identify the extension and perform actions
* on the yang statement, such as transforming the yang.
@ -919,8 +941,8 @@ clixon_plugin_extension_one(clixon_plugin_t *cp,
* @param[in] h Clixon handle
* @param[in] yext Yang node of extension
* @param[in] ys Yang node of (unknown) statement belonging to extension
* @retval 0 OK, all callbacks executed OK
* @retval -1 Error in one callback
* @retval 0 OK, all callbacks executed OK
* @retval -1 Error in one callback
*/
int
clixon_plugin_extension_all(clicon_handle h,
@ -929,7 +951,7 @@ clixon_plugin_extension_all(clicon_handle h,
{
int retval = -1;
clixon_plugin_t *cp = NULL;
while ((cp = clixon_plugin_each(h, cp)) != NULL) {
if (clixon_plugin_extension_one(cp, h, yext, ys) < 0)
goto done;
@ -942,12 +964,12 @@ clixon_plugin_extension_all(clicon_handle h,
/*! Call plugin general-purpose datastore upgrade in one plugin
*
* @param[in] cp Plugin handle
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] db Name of datastore, eg "running", "startup" or "tmp"
* @param[in] xt XML tree. Upgrade this "in place"
* @param[in] msd Module-state diff, info on datastore module-state
* @retval -1 Error
* @retval 0 OK
* @retval -1 Error
* Upgrade datastore on load before or as an alternative to module-specific upgrading mechanism
*/
int
@ -961,13 +983,13 @@ clixon_plugin_datastore_upgrade_one(clixon_plugin_t *cp,
int retval = -1;
datastore_upgrade_t *fn;
void *wh = NULL;
if ((fn = cp->cp_api.ca_datastore_upgrade) != NULL){
wh = NULL;
if (plugin_context_check(h, &wh, cp->cp_name, __FUNCTION__) < 0)
goto done;
if (fn(h, db, xt, msd) < 0) {
if (clicon_errno < 0)
if (clicon_errno < 0)
clicon_log(LOG_WARNING, "%s: Internal error: Datastore upgrade callback in plugin: %s returned -1 but did not make a clicon_err call",
__FUNCTION__, cp->cp_name);
goto done;
@ -982,7 +1004,7 @@ clixon_plugin_datastore_upgrade_one(clixon_plugin_t *cp,
/*! Call plugin general-purpose datastore upgrade in all plugins
*
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] db Name of datastore, eg "running", "startup" or "tmp"
* @param[in] xt XML tree. Upgrade this "in place"
* @param[in] msd Module-state diff, info on datastore module-state
@ -998,7 +1020,7 @@ clixon_plugin_datastore_upgrade_all(clicon_handle h,
{
int retval = -1;
clixon_plugin_t *cp = NULL;
while ((cp = clixon_plugin_each(h, cp)) != NULL) {
if (clixon_plugin_datastore_upgrade_one(cp, h, db, xt, msd) < 0)
goto done;
@ -1032,13 +1054,13 @@ clixon_plugin_yang_mount_one(clixon_plugin_t *cp,
int retval = -1;
yang_mount_t *fn;
void *wh = NULL;
if ((fn = cp->cp_api.ca_yang_mount) != NULL){
wh = NULL;
if (plugin_context_check(h, &wh, cp->cp_name, __FUNCTION__) < 0)
goto done;
if (fn(h, xt, config, vl, yanglib) < 0) {
if (clicon_errno < 0)
if (clicon_errno < 0)
clicon_log(LOG_WARNING, "%s: Internal error: Yang mount callback in plugin: %s returned -1 but did not make a clicon_err call",
__FUNCTION__, cp->cp_name);
goto done;
@ -1070,7 +1092,7 @@ clixon_plugin_yang_mount_all(clicon_handle h,
{
int retval = -1;
clixon_plugin_t *cp = NULL;
while ((cp = clixon_plugin_each(h, cp)) != NULL) {
if (clixon_plugin_yang_mount_one(cp, h, xt, config, vl, yanglib) < 0)
goto done;
@ -1085,7 +1107,6 @@ clixon_plugin_yang_mount_all(clicon_handle h,
/*! Call plugin YANG schema patch
*
* @param[in] cp Plugin handle
* @param[in] h Clixon handle
* @param[in] ymod YANG module
@ -1100,13 +1121,13 @@ clixon_plugin_yang_patch_one(clixon_plugin_t *cp,
int retval = -1;
yang_patch_t *fn;
void *wh = NULL;
if ((fn = cp->cp_api.ca_yang_patch) != NULL){
wh = NULL;
if (plugin_context_check(h, &wh, cp->cp_name, __FUNCTION__) < 0)
goto done;
if (fn(h, ymod) < 0) {
if (clicon_errno < 0)
if (clicon_errno < 0)
clicon_log(LOG_WARNING, "%s: Internal error: Yang patch callback in plugin: %s returned -1 but did not make a clicon_err call",
__FUNCTION__, cp->cp_name);
goto done;
@ -1132,7 +1153,7 @@ clixon_plugin_yang_patch_all(clicon_handle h,
{
int retval = -1;
clixon_plugin_t *cp = NULL;
while ((cp = clixon_plugin_each(h, cp)) != NULL) {
if (clixon_plugin_yang_patch_one(cp, h, ymod) < 0)
goto done;
@ -1153,10 +1174,10 @@ rpc_callback_dump(clicon_handle h)
rpc_callback_t *rc;
plugin_module_struct *ms = plugin_module_struct_get(h);
clicon_debug(1, "%s--------------", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s--------------", __FUNCTION__);
if ((rc = ms->ms_rpc_callbacks) != NULL)
do {
clicon_debug(1, "%s %s", __FUNCTION__, rc->rc_name);
clixon_debug(CLIXON_DBG_DEFAULT, "%s %s", __FUNCTION__, rc->rc_name);
rc = NEXTQ(rpc_callback_t *, rc);
} while (rc != ms->ms_rpc_callbacks);
return 0;
@ -1177,14 +1198,14 @@ rpc_callback_dump(clicon_handle h)
int
rpc_callback_register(clicon_handle h,
clicon_rpc_cb cb,
void *arg,
void *arg,
const char *ns,
const char *name)
{
rpc_callback_t *rc = NULL;
plugin_module_struct *ms = plugin_module_struct_get(h);
clicon_debug(1, "%s %s", __FUNCTION__, name);
clixon_debug(CLIXON_DBG_DEFAULT, "%s %s", __FUNCTION__, name);
if (ms == NULL){
clicon_err(OE_PLUGIN, EINVAL, "plugin module not initialized");
goto done;
@ -1252,7 +1273,7 @@ rpc_callback_delete_all(clicon_handle h)
*/
int
rpc_callback_call(clicon_handle h,
cxobj *xe,
cxobj *xe,
void *arg,
int *nrp,
cbuf *cbret)
@ -1283,7 +1304,7 @@ rpc_callback_call(clicon_handle h,
if (plugin_context_check(h, &wh, rc->rc_name, __FUNCTION__) < 0)
goto done;
if (rc->rc_callback(h, xe, cbret, arg, rc->rc_arg) < 0){
clicon_debug(1, "%s Error in: %s", __FUNCTION__, rc->rc_name);
clixon_debug(CLIXON_DBG_DEFAULT, "%s Error in: %s", __FUNCTION__, rc->rc_name);
if (plugin_context_check(h, &wh, rc->rc_name, __FUNCTION__) < 0)
goto done;
goto done;
@ -1305,7 +1326,7 @@ rpc_callback_call(clicon_handle h,
*nrp = nr;
retval = 1; /* 0: none found, >0 nr of handlers called */
done:
clicon_debug(CLIXON_DBG_DETAIL, "%s retval:%d", __FUNCTION__, retval);
clixon_debug(CLIXON_DBG_DETAIL, "%s retval:%d", __FUNCTION__, retval);
return retval;
fail:
retval = 0;
@ -1318,6 +1339,7 @@ rpc_callback_call(clicon_handle h,
*/
/*! Register a RPC action callback by appending a new RPC to a yang action node
*Ä
* @param[in] h clicon handle
* @param[in] ys YANG node where action resides
* @param[in] cb Callback
@ -1336,7 +1358,7 @@ action_callback_register(clicon_handle h,
rpc_callback_t *rc = NULL;
char *name;
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
if (ya == NULL){
clicon_err(OE_DB, EINVAL, "yang node is NULL");
goto done;
@ -1375,7 +1397,7 @@ action_callback_register(clicon_handle h,
*/
int
action_callback_call(clicon_handle h,
cxobj *xe,
cxobj *xe,
cbuf *cbret,
void *arg,
void *regarg)
@ -1387,19 +1409,19 @@ action_callback_call(clicon_handle h,
int nr = 0; /* How many callbacks */
void *wh = NULL;
rpc_callback_t *rc;
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
if (xml_find_action(xe, 1, &xa) < 0)
goto done;
if (xa == NULL){
if (netconf_operation_not_supported(cbret, "application", "Action not found") < 0)
goto done;
goto ok;
goto ok;
}
if ((ya = xml_spec(xa)) == NULL){
if (netconf_operation_not_supported(cbret, "application", "Action spec not found") < 0)
goto done;
goto ok;
goto ok;
}
name = xml_name(xa);
/* Action callback */
@ -1409,7 +1431,7 @@ action_callback_call(clicon_handle h,
if (plugin_context_check(h, &wh, rc->rc_name, __FUNCTION__) < 0)
goto done;
if (rc->rc_callback(h, xa, cbret, arg, rc->rc_arg) < 0){
clicon_debug(1, "%s Error in: %s", __FUNCTION__, rc->rc_name);
clixon_debug(CLIXON_DBG_DEFAULT, "%s Error in: %s", __FUNCTION__, rc->rc_name);
if (plugin_context_check(h, &wh, rc->rc_name, __FUNCTION__) < 0)
goto done;
goto done;
@ -1512,9 +1534,9 @@ upgrade_callback_delete_all(clicon_handle h)
* @param[in] from From revision on the form YYYYMMDD (if DEL or CHANGE)
* @param[in] to To revision on the form YYYYMMDD (if ADD or CHANGE)
* @param[out] cbret Return XML (as string in CLIgen buffer), on invalid
* @retval 1 OK
* @retval 0 Invalid - cbret contains reason as netconf
* @retval -1 Error
* @retval 1 OK
* @retval 0 Invalid - cbret contains reason as netconf
* @retval -1 Error
* @see upgrade_callback_reg_fn which registers the callbacks
*/
int
@ -1548,11 +1570,11 @@ upgrade_callback_call(clicon_handle h,
*/
if (uc->uc_namespace == NULL || strcmp(uc->uc_namespace, ns)==0){
if ((ret = uc->uc_callback(h, xt, ns, op, from, to, uc->uc_arg, cbret)) < 0){
clicon_debug(1, "%s Error in: %s", __FUNCTION__, uc->uc_namespace);
clixon_debug(CLIXON_DBG_DEFAULT, "%s Error in: %s", __FUNCTION__, uc->uc_namespace);
goto done;
}
if (ret == 0){
if (cbuf_len(cbret)==0){
if (cbuf_len(cbret)==0){
clicon_err(OE_CFG, 0, "Validation fail %s(%s): cbret not set",
uc->uc_fnstr, ns);
goto done;
@ -1565,7 +1587,7 @@ upgrade_callback_call(clicon_handle h,
} while (uc != ms->ms_upgrade_callbacks);
retval = 1;
done:
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
clixon_debug(CLIXON_DBG_DEFAULT, "%s retval:%d", __FUNCTION__, retval);
return retval;
fail:
retval =0;
@ -1600,8 +1622,11 @@ clixon_auth_type_int2str(clixon_auth_type_t auth_type)
}
/*! Initialize plugin module by creating a handle holding plugin and callback lists
*
* This should be called once at start by every application
* @param[in] h Clixon handle
* @retval 0 OK
* @retval -1 Error
* @see clixon_plugin_module_exit
*/
int
@ -1627,6 +1652,7 @@ clixon_plugin_module_init(clicon_handle h)
}
/*! Delete plugin module
*
* This should be called once at exit by every application
* @param[in] h Clixon handle
*/

View file

@ -169,12 +169,13 @@ clixon_proc_sigint(int sig)
}
/*! Fork a child, exec a child and setup socket to child and return to caller
*
* @param[in] argv NULL-terminated Argument vector
* @param[in] sock_flags Socket type/flags, typically SOCK_DGRAM or SOCK_STREAM, see
* @param[out] pid Process-id of child
* @param[out] sock Socket
* @retval O OK
* @retval -1 Error.
* @retval -1 Error.
* @see clixon_proc_socket_close close sockets, kill child and wait for child termination
* @see for flags usage see man sockerpair(2)
*/
@ -239,8 +240,7 @@ clixon_proc_socket(char **argv,
clicon_err(OE_UNIX, errno, "dup2(STDOUT)");
return -1;
}
close(sp[1]);
close(sp[1]);
if (execvp(argv[0], argv) < 0){
clicon_err(OE_UNIX, errno, "execvp(%s)", argv[0]);
return -1;
@ -248,7 +248,7 @@ clixon_proc_socket(char **argv,
exit(-1); /* Shouldnt reach here */
}
clicon_debug(CLIXON_DBG_DEFAULT, "%s child %u sock %d", __FUNCTION__, child, sp[0]);
clixon_debug(CLIXON_DBG_DEFAULT, "%s child %u sock %d", __FUNCTION__, child, sp[0]);
/* Parent */
close(sp[1]);
*pid = child;
@ -262,7 +262,8 @@ clixon_proc_socket(char **argv,
return retval;
}
/*!
/*! Close socket
*
* @see clixon_proc_socket which creates the child and sockets closed and killed here
*/
int
@ -272,7 +273,7 @@ clixon_proc_socket_close(pid_t pid,
int retval = -1;
int status;
clicon_debug(CLIXON_DBG_DEFAULT, "%s pid %u sock %d", __FUNCTION__, pid, sock);
clixon_debug(CLIXON_DBG_DEFAULT, "%s pid %u sock %d", __FUNCTION__, pid, sock);
if (sock != -1)
close(sock); /* usually kills */
@ -280,7 +281,7 @@ clixon_proc_socket_close(pid_t pid,
// usleep(100000); /* Wait for child to finish */
if(waitpid(pid, &status, 0) == pid){
retval = WEXITSTATUS(status);
clicon_debug(CLIXON_DBG_DEFAULT, "%s waitpid status %#x", __FUNCTION__, retval);
clixon_debug(CLIXON_DBG_DEFAULT, "%s waitpid status %#x", __FUNCTION__, retval);
}
return retval;
}
@ -293,7 +294,7 @@ clixon_proc_socket_close(pid_t pid,
* @param[in] fdkeep If -1 keep this filedes open
* @param[out] pid Process id
* @retval 0 OK
* @retval -1 Error.
* @retval -1 Error.
*/
static int
clixon_proc_background(char **argv,
@ -313,7 +314,7 @@ clixon_proc_background(char **argv,
char *flattened;
unsigned argc;
clicon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
if (argv == NULL){
clicon_err(OE_UNIX, EINVAL, "argv is NULL");
goto quit;
@ -350,7 +351,7 @@ clixon_proc_background(char **argv,
char nsfile[PATH_MAX];
int nsfd;
#endif
clicon_debug(CLIXON_DBG_DEFAULT, "%s child", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s child", __FUNCTION__);
clicon_signal_unblock(0);
signal(SIGTSTP, SIG_IGN);
if (chdir("/") < 0){
@ -370,7 +371,7 @@ clixon_proc_background(char **argv,
*/
if (netns != NULL) {
snprintf(nsfile, PATH_MAX, "/var/run/netns/%s", netns); /* see man setns / ip netns */
clicon_debug(CLIXON_DBG_DEFAULT, "%s nsfile:%s", __FUNCTION__, nsfile);
clixon_debug(CLIXON_DBG_DEFAULT, "%s nsfile:%s", __FUNCTION__, nsfile);
/* Change network namespace */
if ((nsfd = open(nsfile, O_RDONLY | O_CLOEXEC)) < 0){
clicon_err(OE_UNIX, errno, "open");
@ -409,7 +410,7 @@ clixon_proc_background(char **argv,
*pid0 = child;
retval = 0;
quit:
clicon_debug(CLIXON_DBG_DEFAULT, "%s retval:%d child:%u", __FUNCTION__, retval, child);
clixon_debug(CLIXON_DBG_DEFAULT, "%s retval:%d child:%u", __FUNCTION__, retval, child);
return retval;
}
@ -504,7 +505,7 @@ clixon_process_register(clicon_handle h,
int retval = -1;
process_entry_t *pe = NULL;
int i;
if (name == NULL){
clicon_err(OE_DB, EINVAL, "name is NULL");
goto done;
@ -514,7 +515,7 @@ clixon_process_register(clicon_handle h,
goto done;
}
clicon_debug(CLIXON_DBG_DEFAULT, "%s name:%s (%s)", __FUNCTION__, name, argv[0]);
clixon_debug(CLIXON_DBG_DEFAULT, "%s name:%s (%s)", __FUNCTION__, name, argv[0]);
if ((pe = malloc(sizeof(process_entry_t))) == NULL) {
clicon_err(OE_DB, errno, "malloc");
@ -554,8 +555,8 @@ clixon_process_register(clicon_handle h,
}
}
pe->pe_callback = callback;
clicon_debug(CLIXON_DBG_DEFAULT, "%s %s ----> %s", __FUNCTION__,
pe->pe_name,
clixon_debug(CLIXON_DBG_DEFAULT, "%s %s ----> %s", __FUNCTION__,
pe->pe_name,
clicon_int2str(proc_state_map, PROC_STATE_STOPPED)
);
pe->pe_state = PROC_STATE_STOPPED;
@ -601,7 +602,7 @@ clixon_process_delete_all(clicon_handle h)
return 0;
}
/*!
/*! Run process
*/
static int
proc_op_run(pid_t pid0,
@ -633,9 +634,9 @@ proc_op_run(pid_t pid0,
}
int
clixon_process_pid(clicon_handle h,
const char *name,
pid_t *pid)
clixon_process_pid(clicon_handle h,
const char *name,
pid_t *pid)
{
int retval = -1;
process_entry_t *pe;
@ -671,8 +672,9 @@ done:
* @param[in] name Name of process
* @param[in] op0 start, stop, restart, status
* @param[in] wrapit If set, call potential callback, if false, dont call it
* @retval -1 Error
* @retval 0 OK
* @retval 0 OK
* @retval -1 Error
* @see upgrade_callback_reg_fn which registers the callbacks
* @note operations are not made directly but postponed by a scheduling the actions.
* This is not really necessary for all operations (like start) but made for all
@ -691,8 +693,8 @@ clixon_process_operation(clicon_handle h,
int sched = 0; /* If set, process action should be scheduled, register a timeout */
int isrunning = 0;
int delay = 0;
clicon_debug(CLIXON_DBG_DEFAULT, "%s name:%s op:%s", __FUNCTION__, name, clicon_int2str(proc_operation_map, op0));
clixon_debug(CLIXON_DBG_DEFAULT, "%s name:%s op:%s", __FUNCTION__, name, clicon_int2str(proc_operation_map, op0));
if (_proc_entry_list == NULL)
goto ok;
if ((pe = _proc_entry_list) != NULL)
@ -705,7 +707,7 @@ clixon_process_operation(clicon_handle h,
goto done;
if (op == PROC_OP_START || op == PROC_OP_STOP || op == PROC_OP_RESTART){
pe->pe_operation = op;
clicon_debug(CLIXON_DBG_DEFAULT, "%s scheduling name: %s pid:%d op: %s", __FUNCTION__,
clixon_debug(CLIXON_DBG_DEFAULT, "%s scheduling name: %s pid:%d op: %s", __FUNCTION__,
name, pe->pe_pid,
clicon_int2str(proc_operation_map, pe->pe_operation));
if (pe->pe_state==PROC_STATE_RUNNING &&
@ -719,7 +721,7 @@ clixon_process_operation(clicon_handle h,
kill(pe->pe_pid, SIGTERM);
delay = 1;
}
clicon_debug(CLIXON_DBG_DEFAULT, "%s %s(%d) %s --%s--> %s", __FUNCTION__,
clixon_debug(CLIXON_DBG_DEFAULT, "%s %s(%d) %s --%s--> %s", __FUNCTION__,
pe->pe_name, pe->pe_pid,
clicon_int2str(proc_state_map, pe->pe_state),
clicon_int2str(proc_operation_map, pe->pe_operation),
@ -730,7 +732,7 @@ clixon_process_operation(clicon_handle h,
sched++;/* start: immediate stop/restart: not immediate: wait timeout */
}
else{
clicon_debug(CLIXON_DBG_DEFAULT, "%s name:%s op %s cancelled by wrap", __FUNCTION__, name, clicon_int2str(proc_operation_map, op0));
clixon_debug(CLIXON_DBG_DEFAULT, "%s name:%s op %s cancelled by wrap", __FUNCTION__, name, clicon_int2str(proc_operation_map, op0));
}
break; /* hit break here */
}
@ -741,7 +743,7 @@ clixon_process_operation(clicon_handle h,
ok:
retval = 0;
done:
clicon_debug(CLIXON_DBG_DEFAULT, "%s retval:%d", __FUNCTION__, retval);
clixon_debug(CLIXON_DBG_DEFAULT, "%s retval:%d", __FUNCTION__, retval);
return retval;
}
@ -750,8 +752,9 @@ clixon_process_operation(clicon_handle h,
* @param[in] h clicon handle
* @param[in] name Name of process
* @param[out] cbret XML status string
* @retval -1 Error
* @retval 0 OK
* @retval 0 OK
* @retval -1 Error
*/
int
clixon_process_status(clicon_handle h,
@ -765,13 +768,13 @@ clixon_process_status(clicon_handle h,
char timestr[28];
int match = 0;
clicon_debug(CLIXON_DBG_DEFAULT, "%s name:%s", __FUNCTION__, name);
clixon_debug(CLIXON_DBG_DEFAULT, "%s name:%s", __FUNCTION__, name);
if (_proc_entry_list != NULL){
pe = _proc_entry_list;
do {
if (strcmp(pe->pe_name, name) == 0){
clicon_debug(CLIXON_DBG_DEFAULT, "%s found %s pid:%d", __FUNCTION__, name, pe->pe_pid);
clixon_debug(CLIXON_DBG_DEFAULT, "%s found %s pid:%d", __FUNCTION__, name, pe->pe_pid);
/* Check if running */
run = 0;
if (pe->pe_pid && proc_op_run(pe->pe_pid, &run) < 0)
@ -781,7 +784,7 @@ clixon_process_status(clicon_handle h,
if (pe->pe_description)
cprintf(cbret, "<description xmlns=\"%s\">%s</description>", CLIXON_LIB_NS, pe->pe_description);
cprintf(cbret, "<command xmlns=\"%s\">", CLIXON_LIB_NS);
/* The command may include any data, including XML (such as restconf -R
/* The command may include any data, including XML (such as restconf -R
* command) and therefore needs explicit encoding */
for (i=0; i<pe->pe_argc-1; i++){
if (i)
@ -815,12 +818,15 @@ clixon_process_status(clicon_handle h,
}
retval = 0;
done:
clicon_debug(CLIXON_DBG_DEFAULT, "%s retval:%d", __FUNCTION__, retval);
clixon_debug(CLIXON_DBG_DEFAULT, "%s retval:%d", __FUNCTION__, retval);
return retval;
}
/*! Go through process list and start all processes that are enabled via config wrap function
*
* @param[in] h Clixon handle
* @retval 0 OK
* @retval -1 Error
* Commit rules should have done this, but there are some cases such as backend -s none mode
* where commits are not made.
*/
@ -832,7 +838,7 @@ clixon_process_start_all(clicon_handle h)
proc_operation op;
int sched = 0; /* If set, process action should be scheduled, register a timeout */
clicon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
if (_proc_entry_list == NULL)
goto ok;
pe = _proc_entry_list;
@ -843,7 +849,7 @@ clixon_process_start_all(clicon_handle h)
if (pe->pe_callback(h, pe, &op) < 0)
goto done;
if (op == PROC_OP_START){
clicon_debug(CLIXON_DBG_DEFAULT, "%s name:%s start", __FUNCTION__, pe->pe_name);
clixon_debug(CLIXON_DBG_DEFAULT, "%s name:%s start", __FUNCTION__, pe->pe_name);
pe->pe_operation = op;
sched++; /* Immediate dont delay for start */
}
@ -854,12 +860,15 @@ clixon_process_start_all(clicon_handle h)
ok:
retval = 0;
done:
clicon_debug(CLIXON_DBG_DEFAULT, "%s retval:%d", __FUNCTION__, retval);
clixon_debug(CLIXON_DBG_DEFAULT, "%s retval:%d", __FUNCTION__, retval);
return retval;
}
/*! Traverse all processes and check pending start/stop/restarts
*
* @param[in] h Clixon handle
* @retval 0 OK
* @retval -1 Error
* Typical cases where postponing process start/stop is necessary:
* (1) at startup, if started before deamoninization, process will get as child of 1
* (2) edit changes or rpc restart especially of restconf where you may saw of your arm and terminate
@ -876,19 +885,19 @@ clixon_process_sched(int fd,
int isrunning; /* Process is actually running */
int sched = 0;
clicon_debug(CLIXON_DBG_DEFAULT, "%s",__FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s",__FUNCTION__);
if (_proc_entry_list == NULL)
goto ok;
pe = _proc_entry_list;
do {
clicon_debug(CLIXON_DBG_DEFAULT, "%s name: %s pid:%d %s --op:%s-->", __FUNCTION__,
clixon_debug(CLIXON_DBG_DEFAULT, "%s name: %s pid:%d %s --op:%s-->", __FUNCTION__,
pe->pe_name, pe->pe_pid, clicon_int2str(proc_state_map, pe->pe_state), clicon_int2str(proc_operation_map, pe->pe_operation));
/* Execute pending operations and not already exiting */
if (pe->pe_operation != PROC_OP_NONE){
switch (pe->pe_state){
case PROC_STATE_EXITING:
switch (pe->pe_operation){
case PROC_OP_STOP:
case PROC_OP_STOP:
case PROC_OP_RESTART: /* Kill again */
isrunning = 0;
if (proc_op_run(pe->pe_pid, &isrunning) < 0)
@ -916,7 +925,7 @@ clixon_process_sched(int fd,
pe->pe_uid, pe->pe_gid, pe->pe_fdkeep,
&pe->pe_pid) < 0)
goto done;
clicon_debug(CLIXON_DBG_DEFAULT,
clixon_debug(CLIXON_DBG_DEFAULT,
"%s %s(%d) %s --%s--> %s", __FUNCTION__,
pe->pe_name, pe->pe_pid,
clicon_int2str(proc_state_map, pe->pe_state),
@ -944,7 +953,7 @@ clixon_process_sched(int fd,
pe->pe_uid, pe->pe_gid, pe->pe_fdkeep,
&pe->pe_pid) < 0)
goto done;
clicon_debug(CLIXON_DBG_DEFAULT,
clixon_debug(CLIXON_DBG_DEFAULT,
"%s %s(%d) %s --%s--> %s", __FUNCTION__,
pe->pe_name, pe->pe_pid,
clicon_int2str(proc_state_map, pe->pe_state),
@ -968,7 +977,7 @@ clixon_process_sched(int fd,
ok:
retval = 0;
done:
clicon_debug(CLIXON_DBG_DEFAULT, "%s retval:%d", __FUNCTION__, retval);
clixon_debug(CLIXON_DBG_DEFAULT, "%s retval:%d", __FUNCTION__, retval);
return retval;
}
@ -979,6 +988,8 @@ clixon_process_sched(int fd,
* 2) A process is started, dont delay
* @param[in] h Clixon handle
* @param[in] delay If 0 dont add a delay, if 1 add a delay
* @retval 0 OK
* @retval -1 Error
*/
static int
clixon_process_sched_register(clicon_handle h,
@ -988,7 +999,7 @@ clixon_process_sched_register(clicon_handle h,
struct timeval t;
struct timeval t1 = {0, 100000}; /* 100ms */
clicon_debug(CLIXON_DBG_DETAIL, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DETAIL, "%s", __FUNCTION__);
gettimeofday(&t, NULL);
if (delay)
timeradd(&t, &t1, &t);
@ -996,14 +1007,18 @@ clixon_process_sched_register(clicon_handle h,
goto done;
retval = 0;
done:
clicon_debug(CLIXON_DBG_DETAIL, "%s retval:%d", __FUNCTION__, retval);
clixon_debug(CLIXON_DBG_DETAIL, "%s retval:%d", __FUNCTION__, retval);
return retval;
}
/*! Go through processes and wait for child processes
*
* Typically we know a child has been killed by SIGCHLD, but we do not know which process it is
* Traverse all known processes and reap them, eg call waitpid() to avoid zombies.
* @param[in] h Clixon handle
* @retval 0 OK
* @retval -1 Error
*/
int
clixon_process_waitpid(clicon_handle h)
@ -1013,12 +1028,12 @@ clixon_process_waitpid(clicon_handle h)
int status = 0;
pid_t wpid;
clicon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
if (_proc_entry_list == NULL)
goto ok;
if ((pe = _proc_entry_list) != NULL)
do {
clicon_debug(CLIXON_DBG_DEFAULT, "%s %s(%d) %s op:%s", __FUNCTION__,
clixon_debug(CLIXON_DBG_DEFAULT, "%s %s(%d) %s op:%s", __FUNCTION__,
pe->pe_name, pe->pe_pid,
clicon_int2str(proc_state_map, pe->pe_state),
clicon_int2str(proc_operation_map, pe->pe_operation));
@ -1026,15 +1041,15 @@ clixon_process_waitpid(clicon_handle h)
&& (pe->pe_state == PROC_STATE_RUNNING || pe->pe_state == PROC_STATE_EXITING)
// && (pe->pe_operation == PROC_OP_STOP || pe->pe_operation == PROC_OP_RESTART)
){
clicon_debug(CLIXON_DBG_DEFAULT, "%s %s waitpid(%d)", __FUNCTION__,
clixon_debug(CLIXON_DBG_DEFAULT, "%s %s waitpid(%d)", __FUNCTION__,
pe->pe_name, pe->pe_pid);
if ((wpid = waitpid(pe->pe_pid, &status, WNOHANG)) == pe->pe_pid){
clicon_debug(CLIXON_DBG_DEFAULT, "%s waitpid(%d) waited", __FUNCTION__, pe->pe_pid);
clixon_debug(CLIXON_DBG_DEFAULT, "%s waitpid(%d) waited", __FUNCTION__, pe->pe_pid);
pe->pe_exit_status = status;
switch (pe->pe_operation){
case PROC_OP_NONE: /* Spontaneous / External termination */
case PROC_OP_STOP:
clicon_debug(CLIXON_DBG_DEFAULT,
clixon_debug(CLIXON_DBG_DEFAULT,
"%s %s(%d) %s --%s--> %s", __FUNCTION__,
pe->pe_name, pe->pe_pid,
clicon_int2str(proc_state_map, pe->pe_state),
@ -1053,7 +1068,7 @@ clixon_process_waitpid(clicon_handle h)
&pe->pe_pid) < 0)
goto done;
gettimeofday(&pe->pe_starttime, NULL);
clicon_debug(CLIXON_DBG_DEFAULT, "%s %s(%d) %s --%s--> %s", __FUNCTION__,
clixon_debug(CLIXON_DBG_DEFAULT, "%s %s(%d) %s --%s--> %s", __FUNCTION__,
pe->pe_name, pe->pe_pid,
clicon_int2str(proc_state_map, pe->pe_state),
clicon_int2str(proc_operation_map, pe->pe_operation),
@ -1069,7 +1084,7 @@ clixon_process_waitpid(clicon_handle h)
break; /* pid is unique */
}
else
clicon_debug(CLIXON_DBG_DEFAULT, "%s waitpid(%d) nomatch:%d", __FUNCTION__,
clixon_debug(CLIXON_DBG_DEFAULT, "%s waitpid(%d) nomatch:%d", __FUNCTION__,
pe->pe_pid, wpid);
}
pe = NEXTQ(process_entry_t *, pe);
@ -1077,6 +1092,6 @@ clixon_process_waitpid(clicon_handle h)
ok:
retval = 0;
done:
clicon_debug(CLIXON_DBG_DEFAULT, "%s retval:%d", __FUNCTION__, retval);
clixon_debug(CLIXON_DBG_DEFAULT, "%s retval:%d", __FUNCTION__, retval);
return retval;
}

View file

@ -88,6 +88,7 @@ struct formatvec{
};
/*! Translate between int and string of tree formats
*
* @see eum format_enum
*/
static struct formatvec _FORMATS[] = {
@ -164,7 +165,6 @@ clicon_msg_encode(uint32_t id,
/* hdr */
msg->op_len = htonl(len);
msg->op_id = htonl(id);
/* body */
va_start(args, format);
vsnprintf(msg->op_body, xmllen, format, args);
@ -185,7 +185,7 @@ clicon_msg_encode(uint32_t id,
* @retval -1 Error with clicon_err called. Includes parse error
*/
int
clicon_msg_decode(struct clicon_msg *msg,
clicon_msg_decode(struct clicon_msg *msg,
yang_stmt *yspec,
uint32_t *id,
cxobj **xml,
@ -195,13 +195,13 @@ clicon_msg_decode(struct clicon_msg *msg,
char *xmlstr;
int ret;
clicon_debug(CLIXON_DBG_DETAIL, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DETAIL, "%s", __FUNCTION__);
/* hdr */
if (id)
*id = ntohl(msg->op_id);
/* body */
xmlstr = msg->op_body;
// XXX clicon_debug(CLIXON_DBG_MSG, "Recv: %s", xmlstr);
// XXX clixon_debug(CLIXON_DBG_MSG, "Recv: %s", xmlstr);
if ((ret = clixon_xml_parse_string(xmlstr, yspec?YB_RPC:YB_NONE, yspec, xml, xerr)) < 0)
goto done;
if (ret == 0)
@ -216,7 +216,7 @@ clicon_msg_decode(struct clicon_msg *msg,
/*! Open local connection using unix domain sockets
*
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] sockpath Unix domain file path
* @retval s Socket
* @retval -1 Error
@ -237,11 +237,11 @@ clicon_connect_unix(clicon_handle h,
addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, sockpath, sizeof(addr.sun_path)-1);
clicon_debug(CLIXON_DBG_DETAIL, "%s: connecting to %s", __FUNCTION__, addr.sun_path);
clixon_debug(CLIXON_DBG_DETAIL, "%s: connecting to %s", __FUNCTION__, addr.sun_path);
if (connect(s, (struct sockaddr *)&addr, SUN_LEN(&addr)) < 0){
if (errno == EACCES)
clicon_err(OE_CFG, errno, "connecting unix socket: %s. "
"Is user not member of group: \"%s\"?",
"Is user not member of group: \"%s\"?",
sockpath, clicon_sock_group(h));
else
clicon_err(OE_CFG, errno, "connecting unix socket: %s", sockpath);
@ -267,9 +267,9 @@ atomicio_sig_handler(int arg)
* @param[in] n Number of bytes to read/write, loop until done
*/
static ssize_t
atomicio(ssize_t (*fn) (int, void *, size_t),
int fd,
void *s0,
atomicio(ssize_t (*fn) (int, void *, size_t),
int fd,
void *s0,
size_t n)
{
char *s = s0;
@ -307,6 +307,8 @@ atomicio(ssize_t (*fn) (int, void *, size_t),
* @param[in] msg Byte stream
* @param[in] len Length of byte stream
* @param[in] file Calling file name
* @retval 0 OK
* @retval -1 Error
*/
static int
msg_hex(int dbglevel,
@ -317,8 +319,8 @@ msg_hex(int dbglevel,
int retval = -1;
cbuf *cb = NULL;
int i;
if ((dbglevel & clicon_debug_get()) == 0) /* compare debug level with global variable */
if ((dbglevel & clixon_debug_get()) == 0) /* compare debug level with global variable */
goto ok;
if ((cb = cbuf_new()) == NULL){
clicon_err(OE_CFG, errno, "cbuf_new");
@ -328,7 +330,7 @@ msg_hex(int dbglevel,
for (i=0; i<len; i++){
cprintf(cb, "%02x", ((char*)msg)[i]&0xff);
if ((i+1)%32==0){
clicon_debug(dbglevel, "%s", cbuf_get(cb));
clixon_debug(dbglevel, "%s", cbuf_get(cb));
cbuf_reset(cb);
cprintf(cb, "%s:", file);
}
@ -336,7 +338,7 @@ msg_hex(int dbglevel,
if ((i+1)%4==0)
cprintf(cb, " ");
}
clicon_debug(dbglevel, "%s", cbuf_get(cb));
clixon_debug(dbglevel, "%s", cbuf_get(cb));
ok:
retval = 0;
done:
@ -355,21 +357,21 @@ msg_hex(int dbglevel,
* @see clicon_msg_send1 using plain NETCONF
*/
int
clicon_msg_send(int s,
clicon_msg_send(int s,
const char *descr,
struct clicon_msg *msg)
{
{
int retval = -1;
int e;
clicon_debug(CLIXON_DBG_DETAIL, "%s: send msg len=%d", __FUNCTION__, ntohl(msg->op_len));
clixon_debug(CLIXON_DBG_DETAIL, "%s: send msg len=%d", __FUNCTION__, ntohl(msg->op_len));
if (descr)
clicon_debug(CLIXON_DBG_MSG, "Send [%s]: %s", descr, msg->op_body);
clixon_debug(CLIXON_DBG_MSG, "Send [%s]: %s", descr, msg->op_body);
else{
clicon_debug(CLIXON_DBG_MSG, "Send: %s", msg->op_body);
clixon_debug(CLIXON_DBG_MSG, "Send: %s", msg->op_body);
}
msg_hex(CLIXON_DBG_EXTRA, (char*)msg, ntohl(msg->op_len), __FUNCTION__);
if (atomicio((ssize_t (*)(int, void *, size_t))write,
if (atomicio((ssize_t (*)(int, void *, size_t))write,
s, msg, ntohl(msg->op_len)) < 0){
e = errno;
clicon_err(OE_CFG, e, "atomicio");
@ -408,7 +410,7 @@ clicon_msg_rcv(int s,
int intr,
struct clicon_msg **msg,
int *eof)
{
{
int retval = -1;
struct clicon_msg hdr;
int hlen;
@ -416,13 +418,13 @@ clicon_msg_rcv(int s,
sigfn_t oldhandler;
uint32_t mlen;
clicon_debug(CLIXON_DBG_DETAIL, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DETAIL, "%s", __FUNCTION__);
*eof = 0;
if (intr){
clicon_signal_unblock(SIGINT);
set_signal_flags(SIGINT, 0, atomicio_sig_handler, &oldhandler);
}
if ((hlen = atomicio(read, s, &hdr, sizeof(hdr))) < 0){
if ((hlen = atomicio(read, s, &hdr, sizeof(hdr))) < 0){
if (intr && _atomicio_sig)
;
else
@ -439,9 +441,9 @@ clicon_msg_rcv(int s,
goto done;
}
mlen = ntohl(hdr.op_len);
clicon_debug(CLIXON_DBG_EXTRA, "op-len:%u op-id:%u",
clixon_debug(CLIXON_DBG_EXTRA, "op-len:%u op-id:%u",
mlen, ntohl(hdr.op_id));
clicon_debug(CLIXON_DBG_DETAIL, "%s: rcv msg len=%d",
clixon_debug(CLIXON_DBG_DETAIL, "%s: rcv msg len=%d",
__FUNCTION__, mlen);
if (mlen <= sizeof(hdr)){
clicon_err(OE_PROTO, 0, "op_len:%u too short", mlen);
@ -453,7 +455,7 @@ clicon_msg_rcv(int s,
goto done;
}
memcpy(*msg, &hdr, hlen);
if ((len2 = atomicio(read, s, (*msg)->op_body, mlen - sizeof(hdr))) < 0){
if ((len2 = atomicio(read, s, (*msg)->op_body, mlen - sizeof(hdr))) < 0){
clicon_err(OE_PROTO, errno, "read");
goto done;
}
@ -470,13 +472,13 @@ clicon_msg_rcv(int s,
goto ok;
}
if (descr)
clicon_debug(CLIXON_DBG_MSG, "Recv [%s]: %s", descr, (*msg)->op_body);
clixon_debug(CLIXON_DBG_MSG, "Recv [%s]: %s", descr, (*msg)->op_body);
else
clicon_debug(CLIXON_DBG_MSG, "Recv: %s", (*msg)->op_body);
clixon_debug(CLIXON_DBG_MSG, "Recv: %s", (*msg)->op_body);
ok:
retval = 0;
done:
clicon_debug(CLIXON_DBG_DETAIL, "%s retval:%d", __FUNCTION__, retval);
clixon_debug(CLIXON_DBG_DETAIL, "%s retval:%d", __FUNCTION__, retval);
if (intr){
set_signal(SIGINT, oldhandler, NULL);
clicon_signal_block(SIGINT);
@ -509,7 +511,7 @@ clicon_msg_rcv1(int s,
int xml_state = 0;
int poll;
clicon_debug(CLIXON_DBG_DETAIL, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DETAIL, "%s", __FUNCTION__);
*eof = 0;
memset(buf, 0, sizeof(buf));
while (1){
@ -547,12 +549,12 @@ clicon_msg_rcv1(int s,
} /* while */
ok:
if (descr)
clicon_debug(CLIXON_DBG_MSG, "Recv [%s]: %s", descr, cbuf_get(cb));
clixon_debug(CLIXON_DBG_MSG, "Recv [%s]: %s", descr, cbuf_get(cb));
else
clicon_debug(CLIXON_DBG_MSG, "Recv: %s", cbuf_get(cb));
clixon_debug(CLIXON_DBG_MSG, "Recv: %s", cbuf_get(cb));
retval = 0;
done:
clicon_debug(CLIXON_DBG_DETAIL, "%s done", __FUNCTION__);
clixon_debug(CLIXON_DBG_DETAIL, "%s done", __FUNCTION__);
return retval;
}
@ -566,18 +568,18 @@ clicon_msg_rcv1(int s,
* @see clicon_msg_send using internal IPC header
*/
int
clicon_msg_send1(int s,
clicon_msg_send1(int s,
const char *descr,
cbuf *cb)
{
{
int retval = -1;
clicon_debug(CLIXON_DBG_DETAIL, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DETAIL, "%s", __FUNCTION__);
if (descr)
clicon_debug(CLIXON_DBG_MSG, "Send [%s]: %s", descr, cbuf_get(cb));
clixon_debug(CLIXON_DBG_MSG, "Send [%s]: %s", descr, cbuf_get(cb));
else
clicon_debug(CLIXON_DBG_MSG, "Send: %s", cbuf_get(cb));
if (atomicio((ssize_t (*)(int, void *, size_t))write,
clixon_debug(CLIXON_DBG_MSG, "Send: %s", cbuf_get(cb));
if (atomicio((ssize_t (*)(int, void *, size_t))write,
s, cbuf_get(cb), cbuf_len(cb)) < 0){
clicon_err(OE_CFG, errno, "atomicio");
clicon_log(LOG_WARNING, "%s: write: %s", __FUNCTION__, strerror(errno));
@ -590,7 +592,7 @@ clicon_msg_send1(int s,
/*! Connect to server, send a clicon_msg message and wait for result using unix socket
*
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] msg Internal msg data structure. It has fixed header and variable body.
* @param[in] sockpath Unix domain file path
* @param[out] retdata Returned data as string netconf xml tree.
@ -608,7 +610,7 @@ clicon_rpc_connect_unix(clicon_handle h,
int s = -1;
struct stat sb = {0,};
clicon_debug(CLIXON_DBG_DETAIL, "Send msg on %s", sockpath);
clixon_debug(CLIXON_DBG_DETAIL, "Send msg on %s", sockpath);
if (sock0 == NULL){
clicon_err(OE_NETCONF, EINVAL, "sock0 expected");
goto done;
@ -632,7 +634,7 @@ clicon_rpc_connect_unix(clicon_handle h,
/*! Connect to server, send a clicon_msg message and wait for result using an inet socket
*
* @param[in] h Clicon handle (not used)
* @param[in] h Clixon handle (not used)
* @param[in] dst IPv4 address
* @param[in] port TCP port
* @param[out] retdata Returned data as string netconf xml tree.
@ -651,7 +653,7 @@ clicon_rpc_connect_inet(clicon_handle h,
int s = -1;
struct sockaddr_in addr;
clicon_debug(CLIXON_DBG_DETAIL, "Send msg to %s:%hu", dst, port);
clixon_debug(CLIXON_DBG_DETAIL, "Send msg to %s:%hu", dst, port);
if (sock0 == NULL){
clicon_err(OE_NETCONF, EINVAL, "sock0 expected");
goto done;
@ -661,7 +663,6 @@ clicon_rpc_connect_inet(clicon_handle h,
addr.sin_port = htons(port);
if (inet_pton(addr.sin_family, dst, &addr.sin_addr) != 1)
goto done; /* Could check getaddrinfo */
/* special error handling to get understandable messages (otherwise ENOENT) */
if ((s = socket(addr.sin_family, SOCK_STREAM, 0)) < 0) {
clicon_err(OE_CFG, errno, "socket");
@ -697,7 +698,7 @@ clicon_rpc_connect_inet(clicon_handle h,
int
clicon_rpc(int sock,
const char *descr,
struct clicon_msg *msg,
struct clicon_msg *msg,
char **ret,
int *eof)
{
@ -705,7 +706,7 @@ clicon_rpc(int sock,
struct clicon_msg *reply = NULL;
char *data = NULL;
clicon_debug(CLIXON_DBG_DETAIL, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DETAIL, "%s", __FUNCTION__);
if (clicon_msg_send(sock, descr, msg) < 0)
goto done;
if (clicon_msg_rcv(sock, descr, 0, &reply, eof) < 0)
@ -721,7 +722,7 @@ clicon_rpc(int sock,
ok:
retval = 0;
done:
clicon_debug(CLIXON_DBG_DETAIL, "%s retval:%d", __FUNCTION__, retval);
clixon_debug(CLIXON_DBG_DETAIL, "%s retval:%d", __FUNCTION__, retval);
if (reply)
free(reply);
return retval;
@ -748,7 +749,7 @@ clicon_rpc1(int sock,
{
int retval = -1;
clicon_debug(CLIXON_DBG_DETAIL, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DETAIL, "%s", __FUNCTION__);
if (netconf_framing_preamble(NETCONF_SSH_CHUNKED, msg) < 0)
goto done;
if (netconf_framing_postamble(NETCONF_SSH_CHUNKED, msg) < 0)
@ -759,7 +760,7 @@ clicon_rpc1(int sock,
goto done;
retval = 0;
done:
clicon_debug(CLIXON_DBG_DETAIL, "%s retval:%d", __FUNCTION__, retval);
clixon_debug(CLIXON_DBG_DETAIL, "%s retval:%d", __FUNCTION__, retval);
return retval;
}
@ -772,10 +773,10 @@ clicon_rpc1(int sock,
* @retval 0 OK
* @retval -1 Error
*/
int
send_msg_reply(int s,
int
send_msg_reply(int s,
const char *descr,
char *data,
char *data,
uint32_t datalen)
{
int retval = -1;
@ -809,8 +810,8 @@ send_msg_reply(int s,
* @see send_msg_notify_xml
*/
static int
send_msg_notify(int s,
const char *descr,
send_msg_notify(int s,
const char *descr,
char *event)
{
int retval = -1;
@ -829,7 +830,7 @@ send_msg_notify(int s,
/*! Send a clicon_msg NOTIFY message asynchronously to client
*
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] s Socket to communicate with client
* @param[in] descr Description of peer for logging
* @param[in] xev Event as XML
@ -839,7 +840,7 @@ send_msg_notify(int s,
*/
int
send_msg_notify_xml(clicon_handle h,
int s,
int s,
const char *descr,
cxobj *xev)
{
@ -856,7 +857,7 @@ send_msg_notify_xml(clicon_handle h,
goto done;
retval = 0;
done:
clicon_debug(CLIXON_DBG_DETAIL, "%s %d", __FUNCTION__, retval);
clixon_debug(CLIXON_DBG_DETAIL, "%s %d", __FUNCTION__, retval);
if (cb)
cbuf_free(cb);
return retval;
@ -881,8 +882,8 @@ send_msg_notify_xml(clicon_handle h,
* @endcode
*/
int
detect_endtag(char *tag,
char ch,
detect_endtag(char *tag,
char ch,
int *state)
{
int retval = 0;

View file

@ -136,7 +136,7 @@ clicon_rpc_connect(clicon_handle h,
done:
return retval;
}
/*! Connect to backend or use cached socket and send RPC
*
* @param[in] h Clixon handle
@ -150,7 +150,7 @@ clicon_rpc_connect(clicon_handle h,
*/
static int
clicon_rpc_msg_once(clicon_handle h,
struct clicon_msg *msg,
struct clicon_msg *msg,
int cache,
char **retdata,
int *eof,
@ -158,7 +158,7 @@ clicon_rpc_msg_once(clicon_handle h,
{
int retval = -1;
int s;
if (cache){
if ((s = clicon_client_socket_get(h)) < 0){
if (clicon_rpc_connect(h, &s) < 0)
@ -195,8 +195,8 @@ clicon_rpc_msg_once(clicon_handle h,
* @see clicon_rpc_close_session
*/
int
clicon_rpc_msg(clicon_handle h,
struct clicon_msg *msg,
clicon_rpc_msg(clicon_handle h,
struct clicon_msg *msg,
cxobj **xret0)
{
int retval = -1;
@ -205,7 +205,7 @@ clicon_rpc_msg(clicon_handle h,
int s = -1;
int eof = 0;
clicon_debug(CLIXON_DBG_DETAIL, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DETAIL, "%s", __FUNCTION__);
#ifdef RPC_USERNAME_ASSERT
assert(strstr(msg->op_body, "username")!=NULL); /* XXX */
#endif
@ -225,7 +225,6 @@ clicon_rpc_msg(clicon_handle h,
close(s);
s = -1;
clicon_client_socket_set(h, -1);
clicon_err(OE_PROTO, ESHUTDOWN, "Unexpected close of CLICON_SOCK. Clixon backend daemon may have crashed.");
goto done;
}
@ -253,7 +252,7 @@ clicon_rpc_msg(clicon_handle h,
}
retval = 0;
done:
clicon_debug(CLIXON_DBG_DETAIL, "%s %d", __FUNCTION__, retval);
clixon_debug(CLIXON_DBG_DETAIL, "%s %d", __FUNCTION__, retval);
if (retdata)
free(retdata);
if (xret)
@ -273,8 +272,8 @@ clicon_rpc_msg(clicon_handle h,
* @note xret is populated with yangspec according to standard handle yangspec
*/
int
clicon_rpc_msg_persistent(clicon_handle h,
struct clicon_msg *msg,
clicon_rpc_msg_persistent(clicon_handle h,
struct clicon_msg *msg,
cxobj **xret0,
int *sock0)
{
@ -291,7 +290,7 @@ clicon_rpc_msg_persistent(clicon_handle h,
#ifdef RPC_USERNAME_ASSERT
assert(strstr(msg->op_body, "username")!=NULL); /* XXX */
#endif
clicon_debug(1, "%s request:%s", __FUNCTION__, msg->op_body);
clixon_debug(CLIXON_DBG_DEFAULT, "%s request:%s", __FUNCTION__, msg->op_body);
/* Create a socket and connect to it, either UNIX, IPv4 or IPv6 per config options */
if (clicon_rpc_msg_once(h, msg, 0, &retdata, &eof, &s) < 0)
goto done;
@ -306,7 +305,7 @@ clicon_rpc_msg_persistent(clicon_handle h,
clicon_err(OE_PROTO, ESHUTDOWN, "Unexpected close of CLICON_SOCK. Clixon backend daemon may have crashed.");
goto done;
}
clicon_debug(1, "%s retdata:%s", __FUNCTION__, retdata);
clixon_debug(CLIXON_DBG_DEFAULT, "%s retdata:%s", __FUNCTION__, retdata);
if (retdata){
/* Cannot populate xret here because need to know RPC name (eg "lock") in order to associate yang
@ -351,11 +350,11 @@ session_id_check(clicon_handle h,
{
int retval = -1;
uint32_t id;
if (clicon_session_id_get(h, &id) < 0){ /* Not set yet */
if (clicon_hello_req(h, NULL, NULL, &id) < 0)
goto done;
clicon_session_id_set(h, id);
clicon_session_id_set(h, id);
}
retval = 0;
*session_id = id;
@ -382,7 +381,7 @@ session_id_check(clicon_handle h,
* @see clicon_rpc_netconf_xml xml as tree instead of string
*/
int
clicon_rpc_netconf(clicon_handle h,
clicon_rpc_netconf(clicon_handle h,
char *xmlstr,
cxobj **xret,
int *sp)
@ -428,7 +427,7 @@ clicon_rpc_netconf(clicon_handle h,
* @see clicon_rpc_netconf xml as string instead of tree
*/
int
clicon_rpc_netconf_xml(clicon_handle h,
clicon_rpc_netconf_xml(clicon_handle h,
cxobj *xml,
cxobj **xret,
int *sp)
@ -459,7 +458,7 @@ clicon_rpc_netconf_xml(clicon_handle h,
xml_find_type(xreply, NULL, "rpc-error", CX_ELMNT) == NULL){
yspec = clicon_dbspec_yang(h);
/* Here use rpc name to bind to yang */
if ((ret = xml_bind_yang_rpc_reply(h, xreply, rpcname, yspec, &xerr)) < 0)
if ((ret = xml_bind_yang_rpc_reply(h, xreply, rpcname, yspec, &xerr)) < 0)
goto done;
if (ret == 0){
/* Replace reply with error */
@ -513,9 +512,9 @@ clicon_rpc_netconf_xml(clicon_handle h,
* @note the netconf return message is yang populated, as well as the return data
*/
int
clicon_rpc_get_config(clicon_handle h,
clicon_rpc_get_config(clicon_handle h,
char *username, // XXX: why is this only rpc call with username parameter?
char *db,
char *db,
char *xpath,
cvec *nsc,
char *defaults,
@ -525,13 +524,13 @@ clicon_rpc_get_config(clicon_handle h,
struct clicon_msg *msg = NULL;
cbuf *cb = NULL;
cxobj *xret = NULL;
cxobj *xerr = NULL;
cxobj *xerr = NULL;
cxobj *xd = NULL;
uint32_t session_id;
int ret;
yang_stmt *yspec;
cvec *nscd = NULL;
if (session_id_check(h, &session_id) < 0)
goto done;
if ((cb = cbuf_new()) == NULL){
@ -628,14 +627,14 @@ clicon_rpc_get_config(clicon_handle h,
* @retval -1 Error and logged to syslog
* @note xml arg need to have <config> as top element
* @code
* if (clicon_rpc_edit_config(h, "running", OP_MERGE,
* if (clicon_rpc_edit_config(h, "running", OP_MERGE,
* "<config><a xmlns="urn:example:clixon">4</a></config>") < 0)
* err;
* @endcode
*/
int
clicon_rpc_edit_config(clicon_handle h,
char *db,
clicon_rpc_edit_config(clicon_handle h,
char *db,
enum operation_type op,
char *xmlstr)
{
@ -646,7 +645,7 @@ clicon_rpc_edit_config(clicon_handle h,
cxobj *xerr;
char *username;
uint32_t session_id;
if (session_id_check(h, &session_id) < 0)
goto done;
if ((cb = cbuf_new()) == NULL){
@ -661,7 +660,7 @@ clicon_rpc_edit_config(clicon_handle h,
}
cprintf(cb, " %s", NETCONF_MESSAGE_ID_ATTR); /* XXX: use incrementing sequence */
cprintf(cb, "><edit-config><target><%s/></target>", db);
cprintf(cb, "<default-operation>%s</default-operation>",
cprintf(cb, "<default-operation>%s</default-operation>",
xml_operation2str(op));
if (xmlstr)
cprintf(cb, "%s", xmlstr);
@ -700,8 +699,8 @@ clicon_rpc_edit_config(clicon_handle h,
* @endcode
*/
int
clicon_rpc_copy_config(clicon_handle h,
char *db1,
clicon_rpc_copy_config(clicon_handle h,
char *db1,
char *db2)
{
int retval = -1;
@ -710,7 +709,7 @@ clicon_rpc_copy_config(clicon_handle h,
cxobj *xerr;
char *username;
uint32_t session_id;
cbuf *cb = NULL;
cbuf *cb = NULL;
if (session_id_check(h, &session_id) < 0)
goto done;
@ -759,7 +758,7 @@ clicon_rpc_copy_config(clicon_handle h,
* @endcode
*/
int
clicon_rpc_delete_config(clicon_handle h,
clicon_rpc_delete_config(clicon_handle h,
char *db)
{
int retval = -1;
@ -769,7 +768,7 @@ clicon_rpc_delete_config(clicon_handle h,
char *username;
uint32_t session_id;
cbuf *cb = NULL;
if (session_id_check(h, &session_id) < 0)
goto done;
if ((cb = cbuf_new()) == NULL){
@ -813,7 +812,7 @@ clicon_rpc_delete_config(clicon_handle h,
* @retval -1 Error and logged to syslog
*/
int
clicon_rpc_lock(clicon_handle h,
clicon_rpc_lock(clicon_handle h,
char *db)
{
int retval = -1;
@ -823,7 +822,7 @@ clicon_rpc_lock(clicon_handle h,
char *username;
uint32_t session_id;
cbuf *cb = NULL;
if (session_id_check(h, &session_id) < 0)
goto done;
if ((cb = cbuf_new()) == NULL){
@ -867,7 +866,7 @@ clicon_rpc_lock(clicon_handle h,
* @retval -1 Error and logged to syslog
*/
int
clicon_rpc_unlock(clicon_handle h,
clicon_rpc_unlock(clicon_handle h,
char *db)
{
int retval = -1;
@ -877,7 +876,7 @@ clicon_rpc_unlock(clicon_handle h,
char *username;
uint32_t session_id;
cbuf *cb = NULL;
if (session_id_check(h, &session_id) < 0)
goto done;
if ((cb = cbuf_new()) == NULL){
@ -915,7 +914,7 @@ clicon_rpc_unlock(clicon_handle h,
/*! Get database configuration and state data
*
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] xpath XPath in a filter stmt (or NULL/"" for no filter)
* @param[in] namespace Namespace associated w xpath
* @param[in] nsc Namespace context for filter
@ -963,7 +962,7 @@ clicon_rpc_get(clicon_handle h,
/*! Get database configuration and state data (please use instead of clicon_rpc_get)
*
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] xpath XPath in a filter stmt (or NULL/"" for no filter)
* @param[in] namespace Namespace associated w xpath
* @param[in] nsc Namespace context for filter
@ -1018,8 +1017,8 @@ clicon_rpc_get2(clicon_handle h,
int ret;
yang_stmt *yspec;
cvec *nscd = NULL;
clicon_debug(CLIXON_DBG_DETAIL, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DETAIL, "%s", __FUNCTION__);
if (session_id_check(h, &session_id) < 0)
goto done;
if ((cb = cbuf_new()) == NULL){
@ -1032,12 +1031,12 @@ clicon_rpc_get2(clicon_handle h,
cprintf(cb, " %s:username=\"%s\"", CLIXON_LIB_PREFIX, username);
cprintf(cb, " xmlns:%s=\"%s\"", CLIXON_LIB_PREFIX, CLIXON_LIB_NS);
}
cprintf(cb, " message-id=\"%d\"", netconf_message_id_next(h));
cprintf(cb, " message-id=\"%d\"", netconf_message_id_next(h));
cprintf(cb, "><get");
/* Clixon extension, content=all,config, or nonconfig */
if ((int)content != -1)
cprintf(cb, " %s:content=\"%s\" xmlns:%s=\"%s\"",
CLIXON_LIB_PREFIX,
CLIXON_LIB_PREFIX,
netconf_content_int2str(content),
CLIXON_LIB_PREFIX, CLIXON_LIB_NS);
/* Clixon extension, depth=<level> */
@ -1105,7 +1104,7 @@ clicon_rpc_get2(clicon_handle h,
}
retval = 0;
done:
clicon_debug(CLIXON_DBG_DETAIL, "%s %d", __FUNCTION__, retval);
clixon_debug(CLIXON_DBG_DETAIL, "%s %d", __FUNCTION__, retval);
if (nscd)
cvec_free(nscd);
if (cb)
@ -1121,7 +1120,7 @@ clicon_rpc_get2(clicon_handle h,
/*! Get database configuration and state data collection
*
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] xpath To identify a list/leaf-list
* @param[in] namespace Namespace associated w xpath
* @param[in] nsc Namespace context for filter
@ -1142,7 +1141,7 @@ clicon_rpc_get2(clicon_handle h,
* @note the netconf return message is yang populated, as well as the return data
*/
int
clicon_rpc_get_pageable_list(clicon_handle h,
clicon_rpc_get_pageable_list(clicon_handle h,
char *datastore,
char *xpath,
cvec *nsc, /* namespace context for xpath */
@ -1167,7 +1166,7 @@ clicon_rpc_get_pageable_list(clicon_handle h,
int ret;
yang_stmt *yspec;
cvec *nscd = NULL;
if (datastore == NULL){
clicon_err(OE_XML, EINVAL, "datastore not given");
goto done;
@ -1190,13 +1189,13 @@ clicon_rpc_get_pageable_list(clicon_handle h,
/* Clixon extension, content=all,config, or nonconfig */
if ((int)content != -1)
cprintf(cb, " %s:content=\"%s\" xmlns:%s=\"%s\"",
CLIXON_LIB_PREFIX,
CLIXON_LIB_PREFIX,
netconf_content_int2str(content),
CLIXON_LIB_PREFIX, CLIXON_LIB_NS);
/* Clixon extension, depth=<level> */
if (depth != -1)
cprintf(cb, " %s:depth=\"%d\" xmlns:%s=\"%s\"",
CLIXON_LIB_PREFIX,
CLIXON_LIB_PREFIX,
depth,
CLIXON_LIB_PREFIX, CLIXON_LIB_NS);
/* declare lp prefix in get, so sub-elements dont need to */
@ -1362,7 +1361,7 @@ clicon_rpc_kill_session(clicon_handle h,
char *username;
uint32_t my_session_id; /* Not the one to kill */
cbuf *cb = NULL;
if (session_id_check(h, &my_session_id) < 0)
goto done;
if ((cb = cbuf_new()) == NULL){
@ -1408,7 +1407,7 @@ clicon_rpc_kill_session(clicon_handle h,
* @note error returns are logged but not returned
*/
int
clicon_rpc_validate(clicon_handle h,
clicon_rpc_validate(clicon_handle h,
char *db)
{
int retval = -1;
@ -1418,7 +1417,7 @@ clicon_rpc_validate(clicon_handle h,
char *username;
uint32_t session_id;
cbuf *cb = NULL;
if (session_id_check(h, &session_id) < 0)
goto done;
if ((cb = cbuf_new()) == NULL){
@ -1442,7 +1441,7 @@ clicon_rpc_validate(clicon_handle h,
if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){
clixon_netconf_error(xerr, CLIXON_ERRSTR_VALIDATE_FAILED, NULL);
retval = 0;
goto done;
goto done;
}
retval = 1;
done:
@ -1584,7 +1583,7 @@ clicon_rpc_discard_changes(clicon_handle h)
char *username;
uint32_t session_id;
cbuf *cb = NULL;
if (session_id_check(h, &session_id) < 0)
goto done;
if ((cb = cbuf_new()) == NULL){
@ -1622,7 +1621,7 @@ clicon_rpc_discard_changes(clicon_handle h)
/*! Create a new notification subscription
*
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param{in] stream name of notificatio/log stream (CLICON is predefined)
* @param{in] filter message filter, eg xpath for xml notifications
* @param[out] s0 socket returned where notification mesages will appear
@ -1632,8 +1631,8 @@ clicon_rpc_discard_changes(clicon_handle h)
*/
int
clicon_rpc_create_subscription(clicon_handle h,
char *stream,
char *filter,
char *stream,
char *filter,
int *s0)
{
int retval = -1;
@ -1643,7 +1642,7 @@ clicon_rpc_create_subscription(clicon_handle h,
char *username;
uint32_t session_id;
cbuf *cb = NULL;
if (session_id_check(h, &session_id) < 0)
goto done;
if ((cb = cbuf_new()) == NULL){
@ -1693,7 +1692,7 @@ clicon_rpc_create_subscription(clicon_handle h,
* @retval -1 Error and logged to syslog
*/
int
clicon_rpc_debug(clicon_handle h,
clicon_rpc_debug(clicon_handle h,
int level)
{
int retval = -1;
@ -1756,7 +1755,7 @@ clicon_rpc_debug(clicon_handle h,
* 3 CLICON_BACKEND_RESTCONF_PROCESS is true (so that backend restarts restconf)
*/
int
clicon_rpc_restconf_debug(clicon_handle h,
clicon_rpc_restconf_debug(clicon_handle h,
int level)
{
int retval = -1;
@ -1766,7 +1765,7 @@ clicon_rpc_restconf_debug(clicon_handle h,
char *username;
uint32_t session_id;
cbuf *cb = NULL;
if (session_id_check(h, &session_id) < 0)
goto done;
if ((cb = cbuf_new()) == NULL){
@ -1890,7 +1889,7 @@ clicon_hello_req(clicon_handle h,
}
b = xml_body(x);
if ((ret = parse_uint32(b, id, NULL)) <= 0){
clicon_err(OE_XML, errno, "parse_uint32");
clicon_err(OE_XML, errno, "parse_uint32");
goto done;
}
retval = 0;
@ -1912,7 +1911,7 @@ clicon_hello_req(clicon_handle h,
* @retval -1 Error and logged to syslog
*/
int
clicon_rpc_restart_plugin(clicon_handle h,
clicon_rpc_restart_plugin(clicon_handle h,
char *plugin)
{
int retval = -1;
@ -1922,7 +1921,7 @@ clicon_rpc_restart_plugin(clicon_handle h,
char *username;
uint32_t session_id;
cbuf *cb = NULL;
if (session_id_check(h, &session_id) < 0)
goto done;
if ((cb = cbuf_new()) == NULL){

View file

@ -205,6 +205,7 @@ fail:
}
/*! Transform from XSD regex to posix ERE
*
* The usecase is that Yang (RFC7950) supports XSD regular expressions but
* CLIgen supports POSIX ERE
* POSIX ERE regexps according to man regex(3).
@ -242,7 +243,7 @@ regexp_xsd2posix(char *xsd,
int esc;
int minus = 0;
size_t len;
if ((cb = cbuf_new()) == NULL){
clicon_err(OE_UNIX, errno, "cbuf_new");
goto done;
@ -320,10 +321,10 @@ regexp_xsd2posix(char *xsd,
break;
case 'w': /* word */
//cprintf(cb, "[0-9a-zA-Z_\\\\-]")
cprintf(cb, "[[:alnum:]|_]");
cprintf(cb, "[[:alnum:]|_]");
break;
case 'W': /* inverse of \w */
cprintf(cb, "[^[[:alnum:]|_]]");
cprintf(cb, "[^[[:alnum:]|_]]");
break;
case 'u': {
int n;
@ -369,7 +370,8 @@ regexp_xsd2posix(char *xsd,
/*-------------------------- Generic API functions ------------------------*/
/*! Compilation of regular expression / pattern
* @param[in] h Clicon handle
*
* @param[in] h Clixon handle
* @param[in] regexp Regular expression string in XSD regex format
* @param[out] recomp Compiled regular expression (malloc:d, should be freed)
* @retval 1 OK
@ -408,9 +410,12 @@ regex_compile(clicon_handle h,
}
/*! Execution of (pre-compiled) regular expression / pattern
* @param[in] h Clicon handle
*
* @param[in] h Clixon handle
* @param[in] recomp Compiled regular expression
* @param[in] string Content string to match
* @retval 0 OK
* @retval -1 Error
*/
int
regex_exec(clicon_handle h,
@ -437,8 +442,11 @@ regex_exec(clicon_handle h,
}
/*! Free of (pre-compiled) regular expression / pattern
* @param[in] h Clicon handle
*
* @param[in] h Clixon handle
* @param[in] recomp Compiled regular expression
* @retval 0 OK
* @retval -1 Error
*/
int
regex_free(clicon_handle h,

View file

@ -57,13 +57,14 @@
#include "clixon_sig.h"
/*! Set a signal handler.
*
* @param[in] signo Signal number
* @param[in] handler Function to call when signal occurs
* @param[out] oldhandler Pointer to old handler
*/
int
set_signal(int signo,
void (*handler)(int),
set_signal(int signo,
void (*handler)(int),
void (**oldhandler)(int))
{
return set_signal_flags(signo,
@ -76,15 +77,16 @@ set_signal(int signo,
}
/*! Set a signal handler, but without SA_RESTART
*
* @param[in] signo Signal number
* @param[in] flags Flags (to sigaction)
* @param[in] handler Function to call when signal occurs
* @param[out] oldhandler Pointer to old handler
*/
int
set_signal_flags(int signo,
set_signal_flags(int signo,
int flags,
void (*handler)(int),
void (*handler)(int),
void (**oldhandler)(int))
{
#if defined(HAVE_SIGACTION)
@ -106,39 +108,37 @@ set_signal_flags(int signo,
}
/*! Block signal.
*
* @param[in] sig Signal number to block, If 0, block all signals
*/
void
clicon_signal_block(int sig)
{
sigset_t
set;
sigset_t set;
sigemptyset(&set);
if (sig)
sigaddset(&set, sig);
else
sigfillset(&set);
sigprocmask(SIG_BLOCK, &set, NULL);
sigemptyset(&set);
if (sig)
sigaddset(&set, sig);
else
sigfillset(&set);
sigprocmask(SIG_BLOCK, &set, NULL);
}
/*! Unblock signal.
*
* @param[in] sig Signal number to unblock. If 0, unblock all signals
*/
void
clicon_signal_unblock(int sig)
{
sigset_t
set;
sigset_t set;
sigemptyset(&set);
if (sig)
sigaddset(&set, sig);
else
sigfillset(&set);
sigprocmask(SIG_UNBLOCK, &set, NULL);
sigemptyset(&set);
if (sig)
sigaddset(&set, sig);
else
sigfillset(&set);
sigprocmask(SIG_UNBLOCK, &set, NULL);
}
/*! Save complete signal context
@ -149,7 +149,7 @@ clixon_signal_save(sigset_t *sigset,
{
int retval = -1;
int i;
if (sigprocmask(0, NULL, sigset) < 0){
clicon_err(OE_UNIX, errno, "sigprocmask");
goto done;
@ -167,7 +167,9 @@ clixon_signal_save(sigset_t *sigset,
/*! Restore complete signal context
*
* Note: sigaction may not restore SIGKILL or SIGSTOP, which cannot be caught or ignored.
* @retval 0 OK
* @retval -1 Error
* @note: sigaction may not restore SIGKILL or SIGSTOP, which cannot be caught or ignored.
*/
int
clixon_signal_restore(sigset_t *sigset,
@ -175,7 +177,7 @@ clixon_signal_restore(sigset_t *sigset,
{
int retval = -1;
int i;
if (sigprocmask(SIG_SETMASK, sigset, NULL) < 0){
clicon_err(OE_UNIX, errno, "sigprocmask");
goto done;
@ -197,8 +199,7 @@ clixon_signal_restore(sigset_t *sigset,
*
* @param[in] pidfile Name of pidfile
* @param[out] pid Process id of (eventual) existing daemon process
* @retval 0 OK. if pid > 0 old process exists w that pid
* @retval -1 Error, and clicon_err() called
* @retval 0 OK. if pid > 0 old process exists w that pid
*/
int
pidfile_get_fd(FILE *f,
@ -207,7 +208,7 @@ pidfile_get_fd(FILE *f,
char *ptr;
char buf[32];
pid_t pid;
*pid0 = 0;
ptr = fgets(buf, sizeof(buf), f);
if (ptr != NULL && (pid = atoi(ptr)) > 1) {
@ -224,10 +225,9 @@ pidfile_get_fd(FILE *f,
* @param[in] pidfile Name of pidfile
* @param[out] pid Process id of (eventual) existing daemon process
* @retval 0 OK. if pid > 0 old process exists w that pid
* @retval -1 Error, and clicon_err() called
*/
int
pidfile_get(char *pidfile,
pidfile_get(char *pidfile,
pid_t *pid)
{
FILE *f;
@ -245,7 +245,7 @@ pidfile_get(char *pidfile,
*
* @param[in] pid Process id
* @retval 0 Killed OK
* @retval -1 Could not kill.
* @retval -1 Could not kill.
* Maybe should not belong to pidfile code,..
*/
int
@ -274,13 +274,15 @@ pidfile_zapold(pid_t pid)
/*! Write a pid-file
*
* @param[in] pidfile Name of pidfile
* @param[in] pidfile Name of pidfile
* @retval 0 OK
* @retval -1 Error
*/
int
pidfile_write(char *pidfile)
{
FILE *f = NULL;
int retval = -1;
FILE *f = NULL;
/* Here, there should be no old agent and no pidfile */
if ((f = fopen(pidfile, "w")) == NULL){
@ -289,12 +291,12 @@ pidfile_write(char *pidfile)
else
clicon_err(OE_DAEMON, errno, "Creating pid-file %s", pidfile);
goto done;
}
}
if ((retval = fprintf(f, "%ld\n", (long) getpid())) < 1){
clicon_err(OE_DAEMON, errno, "Could not write pid to %s", pidfile);
goto done;
}
clicon_debug(1, "Opened pidfile %s with pid %d", pidfile, getpid());
clixon_debug(CLIXON_DBG_DEFAULT, "Opened pidfile %s with pid %d", pidfile, getpid());
retval = 0;
done:
if (f != NULL)

View file

@ -92,7 +92,7 @@
/*! Find an event notification stream given name
*
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] name Name of stream
* @retval es Event notification stream structure
* @retval NULL Not found
@ -116,18 +116,20 @@ stream_find(clicon_handle h,
/*! Add notification event stream
*
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] name Name of stream
* @param[in] description Description of stream
* @param[in] replay_enabled Set if replay possible in stream
* @param[in] retention For replay buffer how much relative to save
* @retval 0 OK
* @retval -1 Error
*/
int
stream_add(clicon_handle h,
const char *name,
const char *name,
const char *description,
const int replay_enabled,
struct timeval *retention)
struct timeval *retention)
{
int retval = -1;
event_stream_t *es;
@ -159,8 +161,9 @@ stream_add(clicon_handle h,
/*! Delete complete notification event stream list (not just single stream)
*
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] force Force deletion of
* @retval 0 OK
*/
int
stream_delete_all(clicon_handle h,
@ -170,7 +173,7 @@ stream_delete_all(clicon_handle h,
struct stream_subscription *ss;
event_stream_t *es;
event_stream_t *head = clicon_stream(h);
while ((es = clicon_stream(h)) != NULL){
DELQ(es, head, event_stream_t *);
clicon_stream_set(h, head);
@ -193,12 +196,12 @@ stream_delete_all(clicon_handle h,
/*! Return stream definition state in XML supporting RFC 8040 and RFC5277
*
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] access If set, include access/location
* @param[out] cb Output buffer containing XML on exit
* @retval 0 OK
* @retval -1 Error
*/
*/
int
stream_get_xml(clicon_handle h,
int access,
@ -222,7 +225,7 @@ stream_get_xml(clicon_handle h,
cprintf(cb, "<encoding>xml</encoding>");
url_prefix = clicon_option_str(h, "CLICON_STREAM_URL");
stream_path = clicon_option_str(h, "CLICON_STREAM_PATH");
cprintf(cb, "<location>%s/%s/%s</location>",
cprintf(cb, "<location>%s/%s/%s</location>",
url_prefix, stream_path, es->es_name);
cprintf(cb, "</access>");
}
@ -237,7 +240,9 @@ stream_get_xml(clicon_handle h,
/*! Check all stream subscription stop timers, set up new timer
*
* @param[in] fd No-op
* @param[in] arg Clicon handle
* @param[in] arg Clixon handle
* @retval 0 OK
* @retval -1 Error
* @note format is given by clixon_event_reg_timeout callback function (fd not needed)
*/
int
@ -255,8 +260,8 @@ stream_timer_setup(int fd,
struct stream_subscription *ss1;
struct stream_replay *r;
struct stream_replay *r1;
clicon_debug(CLIXON_DBG_DETAIL, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DETAIL, "%s", __FUNCTION__);
/* Go thru callbacks and see if any have timed out, if so remove them
* Could also be done by a separate timer.
*/
@ -313,20 +318,9 @@ stream_timer_setup(int fd,
return retval;
}
#ifdef NYI
/*! Delete single notification event stream
* XXX notused
*/
int
stream_del()
{
return 0;
}
#endif
/*! Add an event notification callback to a stream given a callback function
*
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] stream Name of stream
* @param[in] xpath Filter selector - xpath
* @param[in] startime If set, Make a replay
@ -348,7 +342,7 @@ stream_ss_add(clicon_handle h,
event_stream_t *es;
struct stream_subscription *ss = NULL;
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
if ((es = stream_find(h, stream)) == NULL){
clicon_err(OE_CFG, ENOENT, "Stream %s not found", stream);
goto done;
@ -382,7 +376,7 @@ stream_ss_add(clicon_handle h,
/*! Delete event stream subscription to a stream given a callback and arg
*
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] stream Name of stream or NULL for all streams
* @param[in] fn Callback when event occurs
* @param[in] arg Argument to use with callback. Also handle when deleting
@ -395,7 +389,7 @@ stream_ss_rm(clicon_handle h,
struct stream_subscription *ss,
int force)
{
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
DELQ(ss, es->es_subscription, struct stream_subscription *);
/* Remove from upper layers - close socket etc. */
(*ss->ss_fn)(h, 1, NULL, ss->ss_arg);
@ -406,7 +400,7 @@ stream_ss_rm(clicon_handle h,
free(ss->ss_xpath);
free(ss);
}
clicon_debug(1, "%s retval: 0", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s retval: 0", __FUNCTION__);
return 0;
}
@ -436,9 +430,11 @@ stream_ss_find(event_stream_t *es,
/*! Remove stream subscription identified with fn and arg in all streams
*
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] fn Stream callback
* @param[in] arg Argument - typically unique client handle
* @retval 0 OK
* @retval -1 Error
* @see stream_ss_delete For single stream
*/
int
@ -458,7 +454,7 @@ stream_ss_delete_all(clicon_handle h,
}
es = NEXTQ(struct event_stream *, es);
} while (es && es != clicon_stream(h));
}
}
retval = 0;
done:
return retval;
@ -466,6 +462,10 @@ stream_ss_delete_all(clicon_handle h,
/*! Delete a single stream
*
* @param[in] h Clixon handle
* @retval 0 OK
* @retval -1 Error
* @see stream_ss_delete_all (merge with this?)
*/
int
@ -487,7 +487,7 @@ stream_ss_delete(clicon_handle h,
}
es = NEXTQ(struct event_stream *, es);
} while (es && es != clicon_stream(h));
}
}
retval = 0;
done:
return retval;
@ -495,7 +495,7 @@ stream_ss_delete(clicon_handle h,
/*! Stream notify event and distribute to all registered callbacks
*
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] stream Name of event stream. CLICON is predefined as LOG stream
* @param[in] tv Timestamp. Dont notify if subscription has stoptime<tv
* @param[in] event Notification as xml tree
@ -505,15 +505,15 @@ stream_ss_delete(clicon_handle h,
* @see stream_ss_timeout where subscriptions are removed if stoptime<now
*/
static int
stream_notify1(clicon_handle h,
stream_notify1(clicon_handle h,
event_stream_t *es,
struct timeval *tv,
cxobj *xevent)
{
int retval = -1;
struct stream_subscription *ss;
clicon_debug(CLIXON_DBG_DETAIL, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DETAIL, "%s", __FUNCTION__);
/* Go thru all subscriptions and find matches */
if ((ss = es->es_subscription) != NULL)
do {
@ -542,7 +542,7 @@ stream_notify1(clicon_handle h,
/*! Stream notify event and distribute to all registered callbacks
*
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] stream Name of event stream. CLICON is predefined as LOG stream
* @param[in] event Notification as format string according to printf(3)
* @retval 0 OK
@ -554,8 +554,8 @@ stream_notify1(clicon_handle h,
* @see stream_notify1 Internal
*/
int
stream_notify(clicon_handle h,
char *stream,
stream_notify(clicon_handle h,
char *stream,
const char *event, ...)
{
int retval = -1;
@ -569,7 +569,7 @@ stream_notify(clicon_handle h,
struct timeval tv;
event_stream_t *es;
clicon_debug(CLIXON_DBG_DETAIL, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DETAIL, "%s", __FUNCTION__);
if ((es = stream_find(h, stream)) == NULL)
goto ok;
va_start(args, event);
@ -624,7 +624,7 @@ stream_notify(clicon_handle h,
/*! Backward compatible function
*
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] stream Name of event stream. CLICON is predefined as LOG stream
* @param[in] xml Notification as XML stream. Is copied.
* @retval 0 OK
@ -632,8 +632,8 @@ stream_notify(clicon_handle h,
* @see stream_notify Should be merged with this
*/
int
stream_notify_xml(clicon_handle h,
char *stream,
stream_notify_xml(clicon_handle h,
char *stream,
cxobj *xml)
{
int retval = -1;
@ -646,7 +646,7 @@ stream_notify_xml(clicon_handle h,
struct timeval tv;
event_stream_t *es;
clicon_debug(CLIXON_DBG_DETAIL, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DETAIL, "%s", __FUNCTION__);
if ((es = stream_find(h, stream)) == NULL)
goto ok;
if ((yspec = clicon_dbspec_yang(h)) == NULL){
@ -763,6 +763,8 @@ stream_replay_notify(clicon_handle h,
* @param[in] es Stream
* @param[in] tv Timestamp
* @param[in] xv XML
* @retval 0 OK
* @retval -1 Error
*/
int
stream_replay_add(event_stream_t *es,
@ -799,6 +801,8 @@ struct replay_arg{
*
* @param[in] fd Ignore
* @param[in] arg tmp struct including clicon handle, stream and subscription
* @retval 0 OK
* @retval -1 Error
*/
static int
stream_replay_cb(int fd,
@ -808,7 +812,7 @@ stream_replay_cb(int fd,
struct replay_arg *ra= (struct replay_arg*)arg;
event_stream_t *es;
struct stream_subscription *ss;
if (ra == NULL)
goto ok;
if (ra->ra_stream == NULL)
@ -836,6 +840,8 @@ stream_replay_cb(int fd,
* @param[in] stream Name of stream
* @param[in] fn Stream callback
* @param[in] arg Argument - typically unique client handle
* @retval 0 OK
* @retval -1 Error
*/
int
stream_replay_trigger(clicon_handle h,
@ -843,8 +849,8 @@ stream_replay_trigger(clicon_handle h,
stream_fn_t fn,
void *arg)
{
int retval = -1;
struct timeval now;
int retval = -1;
struct timeval now;
struct replay_arg *ra;
if ((ra = malloc(sizeof(*ra))) == NULL){
@ -890,10 +896,10 @@ struct curlbuf{
* realloc. Therefore, we append new data to the userdata buffer.
*/
static size_t
curl_get_cb(void *ptr,
curl_get_cb(void *ptr,
size_t size,
size_t nmemb,
void *userdata)
void *userdata)
{
struct curlbuf *buf = (struct curlbuf *)userdata;
int len;
@ -917,8 +923,8 @@ curl_get_cb(void *ptr,
* @see same function (url_post) in grideye_curl.c
*/
static int
url_post(char *url,
char *postfields,
url_post(char *url,
char *postfields,
char **getdata)
{
int retval = -1;
@ -928,15 +934,15 @@ url_post(char *url,
CURLcode errcode;
/* Try it with curl -X PUT -d '*/
clicon_debug(1, "%s: curl -X POST -d '%s' %s",
clixon_debug(CLIXON_DBG_DEFAULT, "%s: curl -X POST -d '%s' %s",
__FUNCTION__, postfields, url);
/* Set up curl for doing the communication with the controller */
if ((curl = curl_easy_init()) == NULL) {
clicon_debug(1, "curl_easy_init");
clixon_debug(CLIXON_DBG_DEFAULT, "curl_easy_init");
goto done;
}
if ((err = malloc(CURL_ERROR_SIZE)) == NULL) {
clicon_debug(1, "%s: malloc", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s: malloc", __FUNCTION__);
goto done;
}
curl_easy_setopt(curl, CURLOPT_URL, url);
@ -947,12 +953,12 @@ url_post(char *url,
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postfields);
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, strlen(postfields));
if (clicon_debug_get())
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
if (clixon_debug_get())
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
if ((errcode = curl_easy_perform(curl)) != CURLE_OK){
clicon_debug(1, "%s: curl: %s(%d)", __FUNCTION__, err, errcode);
clixon_debug(CLIXON_DBG_DEFAULT, "%s: curl: %s(%d)", __FUNCTION__, err, errcode);
retval = 0;
goto done;
goto done;
}
if (getdata && cb.b_buf){
*getdata = cb.b_buf;
@ -965,21 +971,23 @@ url_post(char *url,
if (cb.b_buf)
free(cb.b_buf);
if (curl)
curl_easy_cleanup(curl); /* cleanup */
curl_easy_cleanup(curl); /* cleanup */
return retval;
}
/*! Stream callback for example stream notification
*
* Push via curl_post to publish stream event
* @param[in] h Clicon handle
* @param[in] h Clixon handle
* @param[in] op Operation: 0 OK, 1 Close
* @param[in] event Event as XML
* @param[in] arg Extra argument provided in stream_ss_add
* @retval 0 OK
* @retval -1 Error
* @see stream_ss_add
*/
static int
stream_publish_cb(clicon_handle h,
static int
stream_publish_cb(clicon_handle h,
int op,
cxobj *event,
void *arg)
@ -991,7 +999,7 @@ stream_publish_cb(clicon_handle h,
char *result = NULL;
char *stream = (char*)arg;
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
if (op != 0)
goto ok;
/* Create pub url */
@ -1016,7 +1024,7 @@ stream_publish_cb(clicon_handle h,
&result) < 0) /* result as xml */
goto done;
if (result)
clicon_debug(1, "%s: %s", __FUNCTION__, result);
clixon_debug(CLIXON_DBG_DEFAULT, "%s: %s", __FUNCTION__, result);
ok:
retval = 0;
done:
@ -1046,12 +1054,12 @@ stream_publish(clicon_handle h,
return retval;
#else
clicon_log(LOG_WARNING, "%s called but CLIXON_PUBLISH_STREAMS not enabled (enable with configure --enable-publish)", __FUNCTION__);
clicon_log_init("xpath", LOG_WARNING, CLICON_LOG_STDERR);
clicon_log_init("xpath", LOG_WARNING, CLICON_LOG_STDERR);
return 0;
#endif
}
int
int
stream_publish_init()
{
#ifdef CLIXON_PUBLISH_STREAMS
@ -1060,7 +1068,7 @@ stream_publish_init()
if (curl_global_init(CURL_GLOBAL_ALL) != 0){
clicon_err(OE_PLUGIN, errno, "curl_global_init");
goto done;
}
}
retval = 0;
done:
return retval;
@ -1069,11 +1077,11 @@ stream_publish_init()
#endif
}
int
int
stream_publish_exit()
{
#ifdef CLIXON_PUBLISH_STREAMS
curl_global_cleanup();
#endif
#endif
return 0;
}

View file

@ -80,8 +80,8 @@
* @see clicon_strsplit
*/
char **
clicon_strsep(char *string,
char *delim,
clicon_strsep(char *string,
char *delim,
int *nvec0)
{
char **vec = NULL;
@ -92,7 +92,7 @@ clicon_strsep(char *string,
size_t siz;
char *s;
char *d;
if ((s = string)==NULL)
goto done;
while (*s){
@ -103,9 +103,9 @@ clicon_strsep(char *string,
/* alloc vector and append copy of string */
siz = (nvec+1)* sizeof(char*) + strlen(string)+1;
if ((vec = (char**)malloc(siz)) == NULL){
clicon_err(OE_UNIX, errno, "malloc");
clicon_err(OE_UNIX, errno, "malloc");
goto done;
}
}
memset(vec, 0, siz);
ptr = (char*)vec + (nvec+1)* sizeof(char*); /* this is where ptr starts */
strcpy(ptr, string);
@ -119,14 +119,14 @@ clicon_strsep(char *string,
/*! Concatenate elements of a string array into a string.
*
* An optional delimiter string can be specified which will be inserted betwen
* An optional delimiter string can be specified which will be inserted between
* each element.
* @retval str Joined string. Free after use.
* @retval NULL Failure
*/
char *
clicon_strjoin(int argc,
char **argv,
clicon_strjoin(int argc,
char **argv,
char *delim)
{
int i;
@ -165,7 +165,7 @@ clixon_string_del_join(char *str1,
{
char *str;
int len;
if (str2 == NULL){
clicon_err(OE_UNIX, EINVAL, "str2 is NULL");
return NULL;
@ -212,7 +212,7 @@ clixon_strsplit(char *string,
{
int retval = -1;
char *str;
if ((str = strchr(string, delim)) == NULL){
if (suffix && (*suffix = strdup(string)) == NULL){
clicon_err(OE_YANG, errno, "strdup");
@ -281,7 +281,7 @@ uri_unreserved(unsigned char in)
* @see xml_chardata_encode
*/
int
uri_percent_encode(char **encp,
uri_percent_encode(char **encp,
const char *fmt, ...)
{
int retval = -1;
@ -310,7 +310,7 @@ uri_percent_encode(char **encp,
/* This is max */
len = strlen(str)*3+1;
if ((enc = malloc(len)) == NULL){
clicon_err(OE_UNIX, errno, "malloc");
clicon_err(OE_UNIX, errno, "malloc");
goto done;
}
memset(enc, 0, len);
@ -344,7 +344,7 @@ uri_percent_encode(char **encp,
* @see uri_percent_encode
*/
int
uri_percent_decode(char *enc,
uri_percent_decode(char *enc,
char **strp)
{
int retval = -1;
@ -353,7 +353,7 @@ uri_percent_decode(char *enc,
char hstr[3];
size_t len;
char *ptr;
if (enc == NULL){
clicon_err(OE_UNIX, EINVAL, "enc is NULL");
goto done;
@ -361,14 +361,14 @@ uri_percent_decode(char *enc,
/* This is max */
len = strlen(enc)+1;
if ((str = malloc(len)) == NULL){
clicon_err(OE_UNIX, errno, "malloc");
clicon_err(OE_UNIX, errno, "malloc");
goto done;
}
memset(str, 0, len);
len = strlen(enc);
j = 0;
for (i=0; i<len; i++){
if (enc[i] == '%' && strlen(enc)-i > 2 &&
if (enc[i] == '%' && strlen(enc)-i > 2 &&
isxdigit(enc[i+1]) && isxdigit(enc[i+2])){
hstr[0] = enc[i+1];
hstr[1] = enc[i+2];
@ -429,7 +429,7 @@ xml_chardata_encode(char **escp,
int cdata; /* when set, skip encoding */
va_list args;
size_t slen;
/* Two steps: (1) read in the complete format string */
va_start(args, fmt); /* dryrun */
fmtlen = vsnprintf(NULL, 0, fmt, args) + 1;
@ -477,7 +477,7 @@ xml_chardata_encode(char **escp,
len++; /* trailing \0 */
/* We know length, allocate encoding buffer */
if ((esc = malloc(len)) == NULL){
clicon_err(OE_UNIX, errno, "malloc");
clicon_err(OE_UNIX, errno, "malloc");
goto done;
}
memset(esc, 0, len);
@ -613,7 +613,7 @@ xml_chardata_decode_ampersand(char *str,
uint32_t code;
cbuf *cb = NULL;
int ret;
if ((semi = index(str, ';')) == NULL)
goto fail;
*semi = '\0';
@ -666,8 +666,10 @@ xml_chardata_decode_ampersand(char *str,
/*! Decode escape characters according to XML definition
*
* @param[out] decp Decoded malloced output string
* @param[in] fmt Encoded input string (stdarg format string)
* @param[out] decp Decoded malloced output string
* @param[in] fmt Encoded input string (stdarg format string)
* @retval 0 OK
* @retval -1 Error
* @see xml_chardata_encode for encoding
*/
int
@ -703,7 +705,7 @@ xml_chardata_decode(char **decp,
* First allocate decoded string, encoded is always >= larger */
slen = strlen(str);
if ((dec = malloc(slen+1)) == NULL){
clicon_err(OE_UNIX, errno, "malloc");
clicon_err(OE_UNIX, errno, "malloc");
goto done;
}
j = 0;
@ -758,9 +760,9 @@ xml_chardata_decode(char **decp,
* XXX differentiate between error and null cvec.
*/
int
uri_str2cvec(char *string,
char delim1,
char delim2,
uri_str2cvec(char *string,
char delim1,
char delim2,
int decode,
cvec **cvp)
{
@ -847,7 +849,7 @@ uri_str2cvec(char *string,
* @note linear search
*/
const char *
clicon_int2str(const map_str2int *mstab,
clicon_int2str(const map_str2int *mstab,
int i)
{
const struct map_str2int *ms;
@ -867,7 +869,7 @@ clicon_int2str(const map_str2int *mstab,
* @see clicon_str2int_search for optimized lookup, but strings must be sorted
*/
int
clicon_str2int(const map_str2int *mstab,
clicon_str2int(const map_str2int *mstab,
char *str)
{
const struct map_str2int *ms;
@ -891,7 +893,7 @@ clicon_str2int(const map_str2int *mstab,
* @note Assumes sorted strings, tree search
*/
static int
str2int_search1(const map_str2int *mstab,
str2int_search1(const map_str2int *mstab,
char *str,
int low,
int upper,
@ -928,13 +930,13 @@ str2int_search1(const map_str2int *mstab,
* @note -1 can not be value
*/
int
clicon_str2int_search(const map_str2int *mstab,
clicon_str2int_search(const map_str2int *mstab,
char *str,
int len)
{
int found;
if (str2int_search1(mstab, str, 0, len, len, &found))
if (str2int_search1(mstab, str, 0, len, len, &found))
return found;
return -1; /* not found */
}
@ -947,7 +949,7 @@ clicon_str2int_search(const map_str2int *mstab,
* @retval NULL Error, not found
*/
char*
clicon_str2str(const map_str2str *mstab,
clicon_str2str(const map_str2str *mstab,
char *str)
{
const struct map_str2str *ms;
@ -984,7 +986,8 @@ nodeid_split(char *nodeid,
return clixon_strsplit(nodeid, ':', prefix, id);
}
/*! Trim blanks from front and end of a string, return new string
/*! Trim blanks from front and end of a string, return new string
*
* @param[in] str
* @retval s Pointer into existing str after trimming blanks
*/
@ -1006,6 +1009,7 @@ clixon_trim(char *str)
}
/*! Trim blanks from front and end of a string, return new string
*
* @param[in] str
* @param[in] trims Characters to trim: a vector of characters
* @retval s Pointer into existing str after trimming blanks
@ -1029,6 +1033,7 @@ clixon_trim2(char *str,
}
/*! check string equals (NULL is equal)
*
* @param[in] s1 String 1
* @param[in] s2 String 2
* @retval 0 Equal
@ -1036,10 +1041,10 @@ clixon_trim2(char *str,
* @retval >0 s1 is greater than s2
*/
int
clicon_strcmp(char *s1,
clicon_strcmp(char *s1,
char *s2)
{
if (s1 == NULL && s2 == NULL)
if (s1 == NULL && s2 == NULL)
return 0;
if (s1 == NULL) /* empty string first */
return -1;
@ -1056,13 +1061,13 @@ clicon_strcmp(char *s1,
* @retval 0 OK
* @retval -1 Error
*/
static int
static int
clixon_unicode2utf8_one(uint16_t uc16,
char *utfstr,
size_t utflen)
{
int retval = -1;
if (utflen < 5){
clicon_err(OE_UNIX, EINVAL, "Length of utfstr is not >=4");
goto done;
@ -1094,7 +1099,7 @@ clixon_unicode2utf8_one(uint16_t uc16,
* @retval 0 OK
* @retval -1 Error
*/
int
int
clixon_unicode2utf8(char *ucstr,
char *utfstr,
size_t utflen)
@ -1141,7 +1146,7 @@ clixon_unicode2utf8(char *ucstr,
*/
#ifndef HAVE_STRNDUP
char *
clicon_strndup(const char *str,
clicon_strndup(const char *str,
size_t len)
{
char *new;

View file

@ -109,6 +109,8 @@ tleaf(cxobj *x)
* @param[in] autocliext How to handle autocli extensions: 0: ignore 1: follow
* @param[in,out] leafl Leaflist state for keeping track of when [] ends
* @param[in,out] leaflname Leaflist state for []
* @retval 0 OK
* @retval -1 Error
* leaflist state:
* 0: No leaflist
* 1: In leaflist
@ -117,16 +119,16 @@ tleaf(cxobj *x)
static int
text2file(cxobj *xn,
clicon_output_cb *fn,
FILE *f,
FILE *f,
int level,
int autocliext,
int *leafl,
char **leaflname)
{
int retval = -1;
cxobj *xc = NULL;
int children=0;
int retval = -1;
int exist = 0;
yang_stmt *yn;
char *value;
@ -171,7 +173,7 @@ text2file(cxobj *xn,
}
}
}
if (*leafl && yn){
if (*leafl && yn){
if (yang_keyword_get(yn) == Y_LEAF_LIST && strcmp(*leaflname, yang_argument_get(yn)) == 0)
;
else{
@ -300,6 +302,8 @@ get_prefix(yang_stmt *yn)
* @param[in] autocliext How to handle autocli extensions: 0: ignore 1: follow
* @param[in,out] leafl Leaflist state for keeping track of when [] ends
* @param[in,out] leaflname Leaflist state for []
* @retval 0 OK
* @retval -1 Error
* leaflist state:
* 0: No leaflist
* 1: In leaflist
@ -313,11 +317,10 @@ text2cbuf(cbuf *cb,
int autocliext,
int *leafl,
char **leaflname)
{
int retval = -1;
cxobj *xc = NULL;
int children=0;
int retval = -1;
int exist = 0;
yang_stmt *yn;
char *value;
@ -351,7 +354,7 @@ text2cbuf(cbuf *cb,
}
}
}
if (*leafl && yn){
if (*leafl && yn){
if (yang_keyword_get(yn) == Y_LEAF_LIST && strcmp(*leaflname, yang_argument_get(yn)) == 0)
;
else{
@ -470,7 +473,7 @@ text2cbuf(cbuf *cb,
*/
int
clixon_text2file(FILE *f,
cxobj *xn,
cxobj *xn,
int level,
clicon_output_cb *fn,
int skiptop,
@ -505,10 +508,12 @@ clixon_text2file(FILE *f,
* @param[in] level Print PRETTYPRINT_INDENT spaces per level in front of each line
* @param[in] skiptop 0: Include top object 1: Skip top-object, only children,
* @param[in] autocliext How to handle autocli extensions: 0: ignore 1: follow
* @retval 0 OK
* @retval -1 Error
*/
int
clixon_text2cbuf(cbuf *cb,
cxobj *xn,
cxobj *xn,
int level,
int skiptop,
int autocliext)
@ -549,7 +554,7 @@ text_diff_keys(cbuf *cb,
cvk = yang_cvec_get(y);
cvi = NULL;
while ((cvi = cvec_each(cvk, cvi)) != NULL) {
keyname = cv_string_get(cvi);
keyname = cv_string_get(cvi);
keyval = xml_find_body(x, keyname);
cprintf(cb, " %s", keyval);
}
@ -565,7 +570,7 @@ text_diff_keys(cbuf *cb,
* @param[in] x1 Second XML tree
* @param[in] level How many spaces to insert before each line
* @param[in] skiptop 0: Include top object 1: Skip top-object, only children,
* @retval 0 Ok
* @retval 0 OK
* @retval -1 Error
* @cod
* cbuf *cb = cbuf_new();
@ -613,7 +618,7 @@ text_diff2cbuf(cbuf *cb,
#endif
}
/* Traverse x0 and x1 in lock-step */
x0c = x1c = NULL;
x0c = x1c = NULL;
x0c = xml_child_each(x0, x0c, CX_ELMNT);
x1c = xml_child_each(x1, x1c, CX_ELMNT);
for (;;){
@ -765,7 +770,9 @@ clixon_text_diff2cbuf(cbuf *cb,
* (2) The reason against is of principal of making the parser design simpler in a bottom-up mode
* The compromise between (1) and (2) is to first parse without YANG (2) and then call a special
* function after YANG binding to populate key tags properly.
* @param[in] x XML node
* @param[in] xn XML node
* @retval 0 OK
* @retval -1 Error
* @see text_mark_bodies where marking of bodies made transformed here
*/
static int
@ -809,7 +816,7 @@ text_populate_list(cxobj *xn)
goto done;
}
xc = NULL;
while ((xc = xml_child_each(xn, xc, CX_ELMNT)) != NULL) {
while ((xc = xml_child_each(xn, xc, CX_ELMNT)) != NULL) {
if (text_populate_list(xc) < 0)
goto done;
}
@ -833,8 +840,8 @@ text_populate_list(cxobj *xn)
* @see _xml_parse for XML variant
* @note Parsing requires YANG, which means yb must be YB_MODULE/_NEXT
*/
static int
_text_syntax_parse(char *str,
static int
_text_syntax_parse(char *str,
yang_bind yb,
yang_stmt *yspec,
cxobj *xt,
@ -847,8 +854,8 @@ _text_syntax_parse(char *str,
cbuf *cberr = NULL;
int failed = 0; /* yang assignment */
cxobj *xc;
clicon_debug(1, "%s %d %s", __FUNCTION__, yb, str);
clixon_debug(CLIXON_DBG_DEFAULT, "%s %d %s", __FUNCTION__, yb, str);
if (yb != YB_MODULE && yb != YB_MODULE_NEXT){
clicon_err(OE_YANG, EINVAL, "yb must be YB_MODULE or YB_MODULE_NEXT");
return -1;
@ -868,7 +875,7 @@ _text_syntax_parse(char *str,
x = NULL;
while ((x = xml_child_each(ts.ts_xtop, x, CX_ELMNT)) != NULL) {
/* Populate, ie associate xml nodes with yang specs
/* Populate, ie associate xml nodes with yang specs
*/
switch (yb){
case YB_MODULE_NEXT:
@ -887,11 +894,11 @@ _text_syntax_parse(char *str,
failed++;
break;
default: /* shouldnt happen */
break;
break;
} /* switch */
/*! Look for YANG lists nodes and convert bodies to keys */
/* Look for YANG lists nodes and convert bodies to keys */
xc = NULL;
while ((xc = xml_child_each(x, xc, CX_ELMNT)) != NULL)
while ((xc = xml_child_each(x, xc, CX_ELMNT)) != NULL)
if (text_populate_list(xc) < 0)
goto done;
}
@ -905,11 +912,11 @@ _text_syntax_parse(char *str,
goto done;
retval = 1;
done:
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
clixon_debug(CLIXON_DBG_DEFAULT, "%s retval:%d", __FUNCTION__, retval);
if (cberr)
cbuf_free(cberr);
clixon_text_syntax_parsel_exit(&ts);
return retval;
return retval;
fail: /* invalid */
retval = 0;
goto done;
@ -925,7 +932,6 @@ _text_syntax_parse(char *str,
* @retval 1 OK and valid
* @retval 0 Invalid (only if yang spec) w xerr set
* @retval -1 Error with clicon_err called
*
* @code
* cxobj *x = NULL;
* if (clixon_text_syntax_parse_string(str, YB_MODULE, yspec, &x, &xerr) < 0)
@ -935,14 +941,14 @@ _text_syntax_parse(char *str,
* @note you need to free the xml parse tree after use, using xml_free()
* @see clixon_text_syntax_parse_file From a file
*/
int
clixon_text_syntax_parse_string(char *str,
int
clixon_text_syntax_parse_string(char *str,
yang_bind yb,
yang_stmt *yspec,
cxobj **xt,
cxobj **xerr)
{
clicon_debug(1, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
if (xt==NULL){
clicon_err(OE_XML, EINVAL, "xt is NULL");
return -1;
@ -966,6 +972,9 @@ clixon_text_syntax_parse_string(char *str,
* @param[in] yspec Yang specification, or NULL
* @param[in,out] xt Pointer to (XML) parse tree. If empty, create.
* @param[out] xerr Reason for invalid returned as netconf err msg
* @retval 1 OK and valid
* @retval 0 Invalid (only if yang spec) w xerr set
* @retval -1 Error with clicon_err called
*
* @code
* cxobj *xt = NULL;
@ -978,10 +987,6 @@ clixon_text_syntax_parse_string(char *str,
* @note May block on file I/O
* @note Parsing requires YANG, which means yb must be YB_MODULE/_NEXT
*
* @retval 1 OK and valid
* @retval 0 Invalid (only if yang spec) w xerr set
* @retval -1 Error with clicon_err called
*
* @see clixon_text_syntax_parse_string
*/
int
@ -1048,7 +1053,7 @@ clixon_text_syntax_parse_file(FILE *fp,
}
if (textbuf)
free(textbuf);
return retval;
return retval;
fail:
retval = 0;
goto done;

View file

@ -39,7 +39,8 @@
/*
* Types
*/
/*! XML parser yacc handler struct */
/*! XML parser yacc handler struct
*/
struct clixon_text_syntax_parse_yacc {
char *ts_parse_string; /* original (copy of) parse string */
int ts_linenum; /* Number of \n in parsed buffer */

View file

@ -62,7 +62,7 @@
#define YY_NO_INPUT
/* typecast macro */
#define _TS ((clixon_text_syntax_yacc *)_ts)
#define _TS ((clixon_text_syntax_yacc *)_ts)
#undef clixon_xml_parsewrap
int clixon_text_syntax_parsewrap(void)

View file

@ -85,21 +85,21 @@
/* Enable for debugging, steals some cycles otherwise */
#if 0
#define _PARSE_DEBUG(s) clicon_debug(1,(s))
#define _PARSE_DEBUG(s) clixon_debug(1,(s))
#else
#define _PARSE_DEBUG(s)
#endif
void
clixon_text_syntax_parseerror(void *arg,
char *s)
char *s)
{
clixon_text_syntax_yacc *ts = (clixon_text_syntax_yacc *)arg;
clicon_err(OE_XML, XMLPARSE_ERRNO, "text_syntax_parse: line %d: %s: at or before: %s",
clicon_err(OE_XML, XMLPARSE_ERRNO, "text_syntax_parse: line %d: %s: at or before: %s",
ts->ts_linenum,
s,
clixon_text_syntax_parsetext);
clixon_text_syntax_parsetext);
return;
}
@ -200,6 +200,7 @@ text_element_create(clixon_xvec *xvec0,
}
/*! Special mechanism to mark bodies so they will not be filtered as whitespace
*
* @see strip_body_objects text_populate_list
*/
static int
@ -207,16 +208,16 @@ text_mark_bodies(clixon_xvec *xv)
{
int i;
cxobj *xb;
for (i=0; i<clixon_xvec_len(xv); i++){
xb = clixon_xvec_i(xv, i);
xml_flag_set(xb, XML_FLAG_BODYKEY);
}
return 0;
}
%}
%}
%%
top : stmt MY_EOF { _PARSE_DEBUG("top->stmt");
@ -229,7 +230,7 @@ stmts : stmts stmt { _PARSE_DEBUG("stmts->stmts stmt");
if (clixon_xvec_merge($1, $2) < 0) YYERROR;
clixon_xvec_free($2);
$$ = $1;
}
}
| { _PARSE_DEBUG("stmts->stmt");
if (($$ = clixon_xvec_new()) == NULL) YYERROR;
}
@ -292,7 +293,7 @@ value : TOKEN { _PARSE_DEBUG("value->TOKEN");
substr : substr TOKEN { _PARSE_DEBUG("substr->substr TOKEN");
$$ = strjoin($1, $2); free($2);}
| { _PARSE_DEBUG("substr->");
$$ = NULL; }
$$ = NULL; }
;
%%

View file

@ -43,7 +43,7 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define _GNU_SOURCE
#define _GNU_SOURCE
#define __USE_GNU
#include <unistd.h> /* For setresuid */
#undef _GNU_SOURCE
@ -64,22 +64,23 @@
#include "clixon_uid.h"
/*! Translate group name to gid. Return -1 if error or not found.
*
* @param[in] name Name of group
* @param[out] gid Group id
* @retval 0 OK
* @retval -1 Error. or not found
* @retval 0 OK
* @retval -1 Error. or not found
*/
int
group_name2gid(const char *name,
group_name2gid(const char *name,
gid_t *gid)
{
int retval = -1;
char buf[1024];
char buf[1024];
struct group g0;
struct group *gr = &g0;
struct group *gtmp;
gr = &g0;
gr = &g0;
/* This leaks memory in ubuntu */
if (getgrnam_r(name, gr, buf, sizeof(buf), &gtmp) < 0){
clicon_err(OE_UNIX, errno, "getgrnam_r(%s)", name);
@ -97,6 +98,7 @@ group_name2gid(const char *name,
}
/*! Translate user name to uid. Return -1 if error or not found.
*
* @param[in] name Name of user
* @param[out] uid User id
* @retval 0 OK
@ -107,7 +109,7 @@ name2uid(const char *name,
uid_t *uid)
{
int retval = -1;
char buf[1024];
char buf[1024];
struct passwd pwbuf;
struct passwd *pwbufp = NULL;
@ -127,20 +129,21 @@ name2uid(const char *name,
}
/*! Translate uid to user name
*
* @param[in] uid User id
* @param[out] name User name (Malloced, need to be freed)
* @retval 0 OK
* @retval -1 Error. or not found
* @retval -1 Error. or not found
*/
int
uid2name(const uid_t uid,
char **name)
{
int retval = -1;
char buf[1024];
char buf[1024];
struct passwd pwbuf = {0,};
struct passwd *pwbufp = NULL;
if (getpwuid_r(uid, &pwbuf, buf, sizeof(buf), &pwbufp) != 0){
clicon_err(OE_UNIX, errno, "getpwuid_r(%u)", uid);
goto done;
@ -164,17 +167,19 @@ uid2name(const uid_t uid,
/* Privileges drop perm, temp and restore
* @see https://www.usenix.org/legacy/events/sec02/full_papers/chen/chen.pdf
*/
/*! Temporarily drop privileges
/*! Temporarily drop privileges
*
* @param[in] new_uid
* @retval 0 OK
* @retval -1 Error
*/
int
drop_priv_temp(uid_t new_uid)
{
#ifdef HAVE_GETRESUID
int retval = -1;
clicon_debug(CLIXON_DBG_DEFAULT, "%s uid:%u", __FUNCTION__, new_uid);
clixon_debug(CLIXON_DBG_DEFAULT, "%s uid:%u", __FUNCTION__, new_uid);
/* XXX: implicit declaration of function 'setresuid' on travis */
if (setresuid(-1, new_uid, geteuid()) < 0){
clicon_err(OE_UNIX, errno, "setresuid");
@ -188,24 +193,27 @@ drop_priv_temp(uid_t new_uid)
done:
return retval;
#else
clicon_debug(CLIXON_DBG_DEFAULT, "%s Drop privileges not implemented on this platform since getresuid is not available", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s Drop privileges not implemented on this platform since getresuid is not available", __FUNCTION__);
return 0;
#endif
}
/*! Permanently drop privileges
/*! Permanently drop privileges
*
* @param[in] new_uid
* @retval 0 OK
* @retval -1 Error
*/
int
drop_priv_perm(uid_t new_uid)
{
#ifdef HAVE_GETRESUID
int retval = -1;
int retval = -1;
uid_t ruid;
uid_t euid;
uid_t suid;
clicon_debug(CLIXON_DBG_DEFAULT, "%s uid:%u", __FUNCTION__, new_uid);
clixon_debug(CLIXON_DBG_DEFAULT, "%s uid:%u", __FUNCTION__, new_uid);
if (setresuid(new_uid, new_uid, new_uid) < 0){
clicon_err(OE_UNIX, errno, "setresuid");
@ -225,7 +233,7 @@ drop_priv_perm(uid_t new_uid)
done:
return retval;
#else
clicon_debug(CLIXON_DBG_DEFAULT, "%s Drop privileges not implemented on this platform since getresuid is not available", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s Drop privileges not implemented on this platform since getresuid is not available", __FUNCTION__);
return 0;
#endif
}
@ -240,7 +248,7 @@ restore_priv(void)
uid_t euid;
uid_t suid;
clicon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
if (getresuid(&ruid, &euid, &suid) < 0){
clicon_err(OE_UNIX, errno, "setresuid");
@ -258,7 +266,7 @@ restore_priv(void)
done:
return retval;
#else
clicon_debug(CLIXON_DBG_DEFAULT, "%s Drop privileges not implemented on this platform since getresuid is not available", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s Drop privileges not implemented on this platform since getresuid is not available", __FUNCTION__);
return 0;
#endif
}

View file

@ -83,6 +83,7 @@
#include "clixon_validate.h"
/*! Validate xml node of type leafref, ensure the value is one of that path's reference
*
* @param[in] xt XML leaf node of type leafref
* @param[in] ys Yang spec of leaf
* @param[in] ytype Yang type statement belonging to the XML node
@ -135,11 +136,11 @@ validate_leafref(cxobj *xt,
yang_stmt *ymod;
cg_var *cv;
int require_instance = 1;
/* require instance */
if ((yreqi = yang_find(ytype, Y_REQUIRE_INSTANCE, NULL)) != NULL){
if ((cv = yang_cv_get(yreqi)) != NULL) /* shouldnt happen */
require_instance = cv_bool_get(cv);
require_instance = cv_bool_get(cv);
}
/* Find referred XML instances */
if (require_instance == 0)
@ -164,7 +165,7 @@ validate_leafref(cxobj *xt,
goto ok;
if (xml_nsctx_yang(ys, &nsc) < 0)
goto done;
if (xpath_vec(xt, nsc, "%s", &xvec, &xlen, path_arg) < 0)
if (xpath_vec(xt, nsc, "%s", &xvec, &xlen, path_arg) < 0)
goto done;
for (i = 0; i < xlen; i++) {
x = xvec[i];
@ -204,6 +205,7 @@ validate_leafref(cxobj *xt,
}
/*! Validate xml node of type identityref, ensure value is a defined identity
*
* Check if a given node has value derived from base identity. This is
* a run-time check necessary when validating eg netconf.
* Valid values for an identityref are any identities derived from all
@ -242,13 +244,13 @@ validate_identityref(cxobj *xt,
cbuf *cb = NULL;
cvec *idrefvec; /* Derived identityref list: (module:id)**/
yang_stmt *ymod;
if ((cb = cbuf_new()) == NULL){
clicon_err(OE_UNIX, errno, "cbuf_new");
clicon_err(OE_UNIX, errno, "cbuf_new");
goto done;
}
if ((cberr = cbuf_new()) == NULL){
clicon_err(OE_UNIX, errno, "cbuf_new");
clicon_err(OE_UNIX, errno, "cbuf_new");
goto done;
}
/* Get idref value. Then see if this value is derived from ytype.
@ -280,7 +282,7 @@ validate_identityref(cxobj *xt,
ymod = yang_find_module_by_prefix_yspec(ys_spec(ys), prefix);
}
if (ymod == NULL){
cprintf(cberr, "Identityref validation failed, %s not derived from %s in %s.yang:%d",
cprintf(cberr, "Identityref validation failed, %s not derived from %s in %s.yang:%d",
node,
yang_argument_get(ybaseid),
yang_argument_get(ys_module(ybaseid)),
@ -290,13 +292,13 @@ validate_identityref(cxobj *xt,
goto fail;
}
cprintf(cb, "%s:%s", yang_argument_get(ymod), id);
idref = cbuf_get(cb);
/* Here check if node is in the derived node list of the base identity
idref = cbuf_get(cb);
/* Here check if node is in the derived node list of the base identity
* The derived node list is a cvec computed XXX
*/
idrefvec = yang_cvec_get(ybaseid);
if (cvec_find(idrefvec, idref) == NULL){
cprintf(cberr, "Identityref validation failed, %s not derived from %s in %s.yang:%d",
cprintf(cberr, "Identityref validation failed, %s not derived from %s in %s.yang:%d",
node,
yang_argument_get(ybaseid),
yang_argument_get(ys_module(ybaseid)),
@ -322,7 +324,8 @@ validate_identityref(cxobj *xt,
}
/*! Validate an RPC node
* @param[in] h Clicon handle
*
* @param[in] h Clixon handle
* @param[in] xrpc XML node to be validated
* @param[in] expanddefault
* @param[out] xret Error XML tree. Free with xml_free after use
@ -375,7 +378,7 @@ xml_yang_validate_rpc(clicon_handle h,
char *rpcprefix;
char *namespace = NULL;
int ret;
if (strcmp(xml_name(xrpc), "rpc")){
clicon_err(OE_XML, EINVAL, "Expected RPC");
goto done;
@ -397,7 +400,7 @@ xml_yang_validate_rpc(clicon_handle h,
goto done;
goto fail;
}
if ((ret = xml_yang_validate_all(h, xn, xret)) < 0)
if ((ret = xml_yang_validate_all(h, xn, xret)) < 0)
goto done; /* error or validation fail */
if (ret == 0)
goto fail;
@ -430,7 +433,7 @@ xml_yang_validate_rpc_reply(clicon_handle h,
char *rpcprefix;
char *namespace = NULL;
int ret;
if (strcmp(xml_name(xrpc), "rpc-reply")){
clicon_err(OE_XML, EINVAL, "Expected RPC");
goto done;
@ -458,7 +461,7 @@ xml_yang_validate_rpc_reply(clicon_handle h,
goto done;
goto fail;
}
if ((ret = xml_yang_validate_all(h, xn, xret)) < 0)
if ((ret = xml_yang_validate_all(h, xn, xret)) < 0)
goto done; /* error or validation fail */
if (ret == 0)
goto fail;
@ -496,10 +499,10 @@ xml_yang_validate_rpc_reply(clicon_handle h,
* is present
*/
static int
check_choice(cxobj *xp,
check_choice(cxobj *xp,
yang_stmt *ytchoice,
yang_stmt *ytcase,
cxobj *xt,
cxobj *xt,
yang_stmt *yt,
cxobj **xret)
{
@ -507,7 +510,7 @@ check_choice(cxobj *xp,
cxobj *x;
yang_stmt *y;
yang_stmt *yp;
x = NULL; /* Find a child with same yang spec */
while ((x = xml_child_each(xp, x, CX_ELMNT)) != NULL) {
if (x == xt)
@ -544,6 +547,7 @@ check_choice(cxobj *xp,
}
/*! Check if an xml node xt is a part of a choice and have >1 siblings
*
* @param[in] xt XML node to be validated
* @param[in] yt xt:s yang statement
* @param[out] xret Error XML tree. Free with xml_free after use
@ -554,15 +558,14 @@ check_choice(cxobj *xp,
* XXX does not check: xt is choice and has n children, but there exists a default child
*/
static int
check_choice_child(cxobj *xt,
check_choice_child(cxobj *xt,
yang_stmt *yt,
cxobj **xret)
{
int retval = -1;
yang_stmt *ytp; /* yt:s parent */
yang_stmt *ytcase = NULL; /* yt:s parent case if any */
yang_stmt *ytchoice = NULL;
yang_stmt *ytchoice = NULL;
int ret;
cxobj *xp;
#if 0
@ -570,7 +573,7 @@ check_choice_child(cxobj *xt,
yang_stmt *yp;
yang_stmt *y;
#endif
if ((ytp = yang_parent_get(yt)) == NULL)
goto ok;
/* Return OK if xt is not choice */
@ -632,6 +635,7 @@ check_choice_child(cxobj *xt,
}
/*! Check that an XML tree of type list has valid keys
*
* @param[in] xt XML tree
* @param[in] yt Yang spec of xt of type LIST which is a config true node.
* @param[out] xret Error XML tree. Free with xml_free after use
@ -645,7 +649,7 @@ check_choice_child(cxobj *xt,
* @see xml_yang_validate_list_key_only
*/
static int
check_list_key(cxobj *xt,
check_list_key(cxobj *xt,
yang_stmt *yt,
cxobj **xret)
@ -655,7 +659,7 @@ check_list_key(cxobj *xt,
cvec *cvk = NULL; /* vector of index keys */
cg_var *cvi;
char *keyname;
if (yt == NULL || !yang_config(yt) || yang_keyword_get(yt) != Y_LIST){
clicon_err(OE_YANG, EINVAL, "yt is not a config true list node");
goto done;
@ -668,7 +672,7 @@ check_list_key(cxobj *xt,
cvk = yang_cvec_get(yt); /* Use Y_LIST cache, see ys_populate_list() */
cvi = NULL;
while ((cvi = cvec_each(cvk, cvi)) != NULL) {
keyname = cv_string_get(cvi);
keyname = cv_string_get(cvi);
if (xml_find_type(xt, NULL, keyname, CX_ELMNT) == NULL){
if (xret){
cbuf *cb = NULL;
@ -676,7 +680,7 @@ check_list_key(cxobj *xt,
enum rfc_6020 keyw;
if ((cb = cbuf_new()) == NULL){
clicon_err(OE_UNIX, errno, "cbuf_new");
clicon_err(OE_UNIX, errno, "cbuf_new");
goto done;
}
ymod = ys_module(yt);
@ -701,6 +705,7 @@ check_list_key(cxobj *xt,
}
/*! Go through all case:s children, ensure all mandatory nodes are marked, else error. Then clear
*
* @retval 1 Validation OK
* @retval 0 Validation failed (xret set)
* @retval -1 Error
@ -750,6 +755,7 @@ choice_mandatory_check(cxobj *xt,
/*! Find yang node which is ancestor of ys (or ys itself) and child of ytop
*
* Assume tree: ytop ... ys
* Return: ytop --- ymp --- ym ... ys
* @retval: 0 No match
@ -765,7 +771,7 @@ yang_ancestor_child(yang_stmt *ys,
yang_stmt *y;
yang_stmt *yprev = NULL;
yang_stmt *yp;
y = ys;
while (y != NULL){
yp = yang_parent_get(y);
@ -818,7 +824,7 @@ check_mandatory_case(cxobj *xt,
yang_stmt *ycnew;
yang_stmt *ycase;
int ret;
ycase = NULL;
x = NULL;
while ((x = xml_child_each(xt, x, CX_ELMNT)) != NULL) {
@ -830,7 +836,7 @@ check_mandatory_case(cxobj *xt,
goto done;
if (ret == 1){
if (yang_flag_get(ym, YANG_FLAG_MARK) != 0){
clicon_debug(1, "%s Already marked, shouldnt happen", __FUNCTION__);
clixon_debug(CLIXON_DBG_DEFAULT, "%s Already marked, shouldnt happen", __FUNCTION__);
}
yang_flag_set(ym, YANG_FLAG_MARK);
}
@ -872,6 +878,7 @@ check_mandatory_case(cxobj *xt,
}
/*! Check if an xml node lacks mandatory children
*
* @param[in] xt XML node to be validated
* @param[in] yt xt:s yang statement
* @param[out] xret Error XML tree. Free with xml_free after use
@ -880,7 +887,7 @@ check_mandatory_case(cxobj *xt,
* @retval -1 Error
*/
static int
check_mandatory(cxobj *xt,
check_mandatory(cxobj *xt,
yang_stmt *yt,
cxobj **xret)
@ -892,7 +899,7 @@ check_mandatory(cxobj *xt,
yang_stmt *yp;
cbuf *cb = NULL;
int ret;
if (yt == NULL || !yang_config(yt)){
clicon_err(OE_YANG, EINVAL, "yt is not config true");
goto done;
@ -906,7 +913,7 @@ check_mandatory(cxobj *xt,
yc = NULL;
while ((yc = yn_each(yt, yc)) != NULL) {
/* Choice is more complex because of choice/case structure and possibly hierarchical */
if (yang_keyword_get(yc) == Y_CHOICE){
if (yang_keyword_get(yc) == Y_CHOICE){
if (yang_xml_mandatory(xt, yc)){
x = NULL;
while ((x = xml_child_each(xt, x, CX_ELMNT)) != NULL) {
@ -924,7 +931,7 @@ check_mandatory(cxobj *xt,
goto fail;
}
}
/*! Check mandatory nodes in case according to RFC7950 7.9.4 */
/* Check mandatory nodes in case according to RFC7950 7.9.4 */
if ((ret = check_mandatory_case(xt, yc, xret)) < 0)
goto done;
if (ret == 0)
@ -938,8 +945,8 @@ check_mandatory(cxobj *xt,
case Y_CONTAINER:
case Y_ANYDATA:
case Y_ANYXML:
case Y_LEAF:
if (yang_config(yc)==0)
case Y_LEAF:
if (yang_config(yc)==0)
break;
/* Find a child with the mandatory yang */
x = NULL;
@ -974,6 +981,7 @@ check_mandatory(cxobj *xt,
}
/*! Validate a single XML node with yang specification for added entry
*
* 1. Check if mandatory leafs present as subs.
* 2. Check leaf values, eg int ranges and string regexps.
* @param[in] xt XML node to be validated
@ -995,7 +1003,7 @@ check_mandatory(cxobj *xt,
*/
int
xml_yang_validate_add(clicon_handle h,
cxobj *xt,
cxobj *xt,
cxobj **xret)
{
int retval = -1;
@ -1089,18 +1097,21 @@ xml_yang_validate_add(clicon_handle h,
}
/*! Some checks done only at edit_config, eg keys in lists
*
* @param[in] xt XML tree
* @param[out] xret Error XML tree. Free with xml_free after use
* @retval 0 OK
* @retval -1 Error
*/
int
xml_yang_validate_list_key_only(cxobj *xt,
xml_yang_validate_list_key_only(cxobj *xt,
cxobj **xret)
{
int retval = -1;
yang_stmt *yt; /* yang spec of xt going in */
int ret;
cxobj *x;
/* if not given by argument (override) use default link
and !Node has a config sub-statement and it is false */
if ((yt = xml_spec(xt)) != NULL &&
@ -1139,7 +1150,7 @@ xml_yang_validate_leaf_union(clicon_handle h,
cxobj *xret1 = NULL;
yang_stmt *ytype; /* resolved type */
char *restype;
/* Enough that one is valid, eg returns 1,otherwise fail */
while ((ytsub = yn_each(yrestype, ytsub)) != NULL){
if (yang_keyword_get(ytsub) != Y_TYPE)
@ -1188,6 +1199,7 @@ xml_yang_validate_leaf_union(clicon_handle h,
}
/*! Validate a single XML node with yang specification for all (not only added) entries
*
* 1. Check leafrefs. Eg you delete a leaf and a leafref references it.
* @param[in] xt XML node to be validated
* @param[out] xret Error XML tree (if retval=0). Free with xml_free after use
@ -1208,7 +1220,7 @@ xml_yang_validate_leaf_union(clicon_handle h,
*/
int
xml_yang_validate_all(clicon_handle h,
cxobj *xt,
cxobj *xt,
cxobj **xret)
{
int retval = -1;
@ -1269,7 +1281,7 @@ xml_yang_validate_all(clicon_handle h,
xml_name(xt),
yang_argument_get(ys_module(yt)),
xpath);
if (xret && netconf_operation_failed_xml(xret, "application",
if (xret && netconf_operation_failed_xml(xret, "application",
cbuf_get(cb)) < 0)
goto done;
goto fail;
@ -1338,7 +1350,7 @@ xml_yang_validate_all(clicon_handle h,
}
cprintf(cb, "Failed MUST xpath '%s' of '%s' in module %s",
xpath, xml_name(xt), yang_argument_get(ys_module(yt)));
if (xret && netconf_operation_failed_xml(xret, "application",
if (xret && netconf_operation_failed_xml(xret, "application",
ye?yang_argument_get(ye):cbuf_get(cb)) < 0)
goto done;
goto fail;
@ -1378,14 +1390,16 @@ xml_yang_validate_all(clicon_handle h,
}
/*! Validate a single XML node with yang specification
* @param[out] xret Error XML tree (if ret == 0). Free with xml_free after use
* @retval 1 Validation OK
* @retval 0 Validation failed (xret set)
* @retval -1 Error
*
* @param[in] h Clixon handle
* @param[out] xret Error XML tree (if ret == 0). Free with xml_free after use
* @retval 1 Validation OK
* @retval 0 Validation failed (xret set)
* @retval -1 Error
*/
int
xml_yang_validate_all_top(clicon_handle h,
cxobj *xt,
cxobj *xt,
cxobj **xret)
{
int ret;
@ -1405,6 +1419,8 @@ xml_yang_validate_all_top(clicon_handle h,
*
* Rewrite return message if errors
* @param[in,out] cbret
* @retval 0 OK
* @retval -1 Error
* @note Parses cbret which seems one time too many
*/
int
@ -1437,7 +1453,7 @@ rpc_reply_check(clicon_handle h,
if ((ret = xml_bind_yang_rpc_reply(h, x, rpcname, yspec, &xret)) < 0)
goto done;
if (ret == 0){
clicon_debug(1, "%s failure when validating:%s", __FUNCTION__, cbuf_get(cbret));
clixon_debug(CLIXON_DBG_DEFAULT, "%s failure when validating:%s", __FUNCTION__, cbuf_get(cbret));
cbuf_reset(cbret);
if (clixon_xml2cbuf(cbret, xret, 0, 0, NULL, -1, 0) < 0)
goto done;
@ -1446,7 +1462,7 @@ rpc_reply_check(clicon_handle h,
if ((ret = xml_yang_validate_rpc_reply(h, x, &xret)) < 0)
goto done;
if (ret == 0){
clicon_debug(1, "%s failure when validating:%s", __FUNCTION__, cbuf_get(cbret));
clixon_debug(CLIXON_DBG_DEFAULT, "%s failure when validating:%s", __FUNCTION__, cbuf_get(cbret));
cbuf_reset(cbret);
if (clixon_xml2cbuf(cbret, xret, 0, 0, NULL, -1, 0) < 0)
goto done;

View file

@ -80,6 +80,7 @@
#include "clixon_validate_minmax.h"
/*! New element last in list, check if already exists if sp return -1
*
* @param[in] vec Vector of existing entries (new is last)
* @param[in] i1 The new entry is placed at vec[i1]
* @param[in] vlen Length of entry
@ -107,8 +108,8 @@ unique_search_xpath(cxobj *x,
char *bi;
/* Collect tuples */
if (xpath_vec(x, nsc, "%s", &xvec, &xveclen, xpath) < 0)
goto done;
if (xpath_vec(x, nsc, "%s", &xvec, &xveclen, xpath) < 0)
goto done;
for (i=0; i<xveclen; i++){
xi = xvec[i];
if ((bi = xml_body(xi)) == NULL)
@ -131,7 +132,7 @@ unique_search_xpath(cxobj *x,
retval = 1;
done:
if (xvec)
free(xvec);
free(xvec);
return retval;
fail:
retval = 0;
@ -186,6 +187,7 @@ check_insert_duplicate(char **vec,
}
/*! Given a list with unique constraint, detect duplicates
*
* @param[in] x The first element in the list (on return the last)
* @param[in] xt The parent of x (a list)
* @param[in] y Its yang spec (Y_LIST)
@ -209,8 +211,8 @@ check_insert_duplicate(char **vec,
* when a list entry is created.
*/
static int
check_unique_list_direct(cxobj *x,
cxobj *xt,
check_unique_list_direct(cxobj *x,
cxobj *xt,
yang_stmt *y,
yang_stmt *yu,
cxobj **xret)
@ -235,7 +237,7 @@ check_unique_list_direct(cxobj *x,
yang_find(y, Y_ORDERED_BY, "user") == NULL);
cvk = yang_cvec_get(yu);
/* nr of unique elements to check */
if ((clen = cvec_len(cvk)) == 0){
if ((clen = cvec_len(cvk)) == 0){
/* No keys: no checks necessary */
goto ok;
}
@ -289,6 +291,7 @@ check_unique_list_direct(cxobj *x,
}
/*! Given a list with unique constraint, detect duplicates
*
* @param[in] x The first element in the list (on return the last)
* @param[in] xt The parent of x (a list)
* @param[in] y Its yang spec (Y_LIST)
@ -312,8 +315,8 @@ check_unique_list_direct(cxobj *x,
* when a list entry is created.
*/
static int
check_unique_list(cxobj *x,
cxobj *xt,
check_unique_list(cxobj *x,
cxobj *xt,
yang_stmt *y,
yang_stmt *yu,
cxobj **xret)
@ -321,7 +324,7 @@ check_unique_list(cxobj *x,
int retval = -1;
cg_var *cvi; /* unique node name */
char **svec = NULL; /* vector of search results */
size_t slen = 0;
size_t slen = 0;
char *xpath0 = NULL;
char *xpath1 = NULL;
int ret;
@ -341,7 +344,7 @@ check_unique_list(cxobj *x,
goto done;
}
/* Check if direct schmeanode-id , ie not xpath */
if (index(xpath0, '/') == NULL){
if (index(xpath0, '/') == NULL){
retval = check_unique_list_direct(x, xt, y, yu, xret);
goto done;
}
@ -404,7 +407,7 @@ check_minmax(cxobj *xp,
yang_stmt *ymin; /* yang min */
yang_stmt *ymax; /* yang max */
cg_var *cv;
if ((ymin = yang_find(y, Y_MIN_ELEMENTS, NULL)) != NULL){
cv = yang_cv_get(ymin);
if (nr < cv_uint32_get(cv)){
@ -431,13 +434,14 @@ check_minmax(cxobj *xp,
}
/*! Check if there is any empty list (no x elements) and check min-elements
* Note recurse for non-presence container
*
* @param[in] xt XML node
* @param[in] yt YANG node
* @param[out] xret Error XML tree. Free with xml_free after use
* @retval 1 Validation OK
* @retval 0 Validation failed (xret set)
* @retval -1 Error
* @note recurse for non-presence container
*/
static int
check_empty_list_minmax(cxobj *xt,
@ -485,7 +489,7 @@ xml_yang_minmax_newlist(cxobj *x,
int retval = -1;
yang_stmt *yu;
int ret;
/* Here new (first element) of lists only
* First check unique keys direct children
*/
@ -518,7 +522,7 @@ xml_yang_minmax_newlist(cxobj *x,
retval = 0;
goto done;
}
/*! Perform gap analysis in a child-vector interval [ye,y]
*
* Gap analysis here meaning if there is a list x with min-element constraint but there are no
@ -566,7 +570,7 @@ xml_yang_minmax_gap_analysis(cxobj *xt,
goto fail;
ye = yn_each(yt, ye);
} while(ye != NULL && /* to avoid livelock (shouldnt happen) */
ye != ych);
ye != ych);
}
*yep = ye;
retval = 1;
@ -657,7 +661,7 @@ xml_yang_minmax_recurse(cxobj *xt,
int nr = 0;
int ret;
yang_stmt *yt;
yt = xml_spec(xt); /* If yt == NULL, then no gap-analysis is done */
while ((x = xml_child_each(xt, x, CX_ELMNT)) != NULL){
if ((y = xml_spec(x)) == NULL)
@ -692,7 +696,7 @@ xml_yang_minmax_recurse(cxobj *xt,
}
else{
/* equal: error */
if (y == yprev){
if (y == yprev){
/* Only lists and leaf-lists are allowed to be more than one */
if (xret && netconf_minmax_elements_xml(xret, xml_parent(x), xml_name(x), 1) < 0)
goto done;
@ -720,10 +724,10 @@ xml_yang_minmax_recurse(cxobj *xt,
goto done;
if (ret == 0)
goto fail;
}
}
}
yprev = y;
}
yprev = y;
}
}
/* After traversal checks;
gap analysis */
@ -736,7 +740,7 @@ xml_yang_minmax_recurse(cxobj *xt,
if ((ret = check_empty_list_minmax(xt, ye, xret)) < 0)
goto done;
if (ret == 0)
goto fail;
goto fail;
} while((ye = yn_each(yt, ye)) != NULL);
}
ret = 1;

File diff suppressed because it is too large Load diff

View file

@ -89,6 +89,7 @@ static int _yang_unknown_anydata = 0;
static int _netconf_message_id_optional = 0;
/*! Kludge to equate unknown XML with anydata
*
* The problem with this is that its global and should be bound to a handle
*/
int
@ -99,6 +100,7 @@ xml_bind_yang_unknown_anydata(int val)
}
/*! Kludge to set message_id_optional
*
* The problem with this is that its global and should be bound to a handle
*/
int
@ -109,6 +111,7 @@ xml_bind_netconf_message_id_optional(int val)
}
/*! After yang binding, bodies of containers and lists are stripped from XML bodies
*
* May apply to other nodes?
* Exception for bodies marked with XML_FLAG_BODYKEY, see text syntax parsing
* @see text_mark_bodies
@ -119,7 +122,7 @@ strip_body_objects(cxobj *xt)
yang_stmt *yt;
enum rfc_6020 keyword;
cxobj *xb;
if ((yt = xml_spec(xt)) != NULL){
keyword = yang_keyword_get(yt);
if (keyword == Y_LIST || keyword == Y_CONTAINER){
@ -257,7 +260,7 @@ populate_self_parent(cxobj *xt,
* @see populate_self_parent
*/
static int
populate_self_top(cxobj *xt,
populate_self_top(cxobj *xt,
yang_stmt *yspec,
cxobj **xerr)
{
@ -374,7 +377,7 @@ populate_self_top(cxobj *xt,
*/
int
xml_bind_yang(clicon_handle h,
cxobj *xt,
cxobj *xt,
yang_bind yb,
yang_stmt *yspec,
cxobj **xerr)
@ -399,7 +402,7 @@ xml_bind_yang(clicon_handle h,
goto done;
}
/*!
/*! Bind yang opt
*
* @param[in] h Clixon handle (sometimes NULL)
* @param[in] xt XML tree node
@ -413,7 +416,7 @@ xml_bind_yang(clicon_handle h,
*/
static int
xml_bind_yang0_opt(clicon_handle h,
cxobj *xt,
cxobj *xt,
yang_bind yb,
yang_stmt *yspec,
cxobj *xsibling,
@ -530,7 +533,7 @@ xml_bind_yang0_opt(clicon_handle h,
*/
int
xml_bind_yang0(clicon_handle h,
cxobj *xt,
cxobj *xt,
yang_bind yb,
yang_stmt *yspec,
cxobj **xerr)
@ -541,7 +544,7 @@ xml_bind_yang0(clicon_handle h,
switch (yb){
case YB_MODULE:
if ((ret = populate_self_top(xt, yspec, xerr)) < 0)
if ((ret = populate_self_top(xt, yspec, xerr)) < 0)
goto done;
break;
case YB_PARENT:
@ -622,7 +625,7 @@ xml_bind_yang_rpc_rpc(clicon_handle h,
/* xml_bind_yang need to have parent with yang spec for
* recursive population to work. Therefore, assign input yang
* to rpc level although not 100% intuitive */
xml_spec_set(x, yi);
xml_spec_set(x, yi);
if ((ret = xml_bind_yang(h, x, YB_PARENT, NULL, xerr)) < 0)
goto done;
if (ret == 0)
@ -681,7 +684,7 @@ xml_bind_yang_rpc_action(clicon_handle h,
}
/*! Find yang spec association of XML node for incoming RPC starting with <rpc>
*
*
* Incoming RPC has an "input" structure that is not taken care of by xml_bind_yang
* @param[in] h Clixon handle
* @param[in] xrpc XML rpc node
@ -713,9 +716,9 @@ xml_bind_yang_rpc(clicon_handle h,
char *rpcname; /* RPC name */
char *name;
cxobj *xc;
opname = xml_name(xrpc);
if ((strcmp(opname, "hello")) == 0){
if ((strcmp(opname, "hello")) == 0){
/* Hello: dont bind, dont appear in any yang spec, just ensure there is nothing apart from
* session-id or capabilities/capability tags
* If erro, just log, drop and close, rpc-error should not be sent since it is not rpc
@ -845,7 +848,7 @@ xml_bind_yang_rpc_reply(clicon_handle h,
char *opname;
cbuf *cberr = NULL;
cxobj *xc;
opname = xml_name(xrpc);
if (strcmp(opname, "rpc-reply")){
if ((cberr = cbuf_new()) == NULL){
@ -874,7 +877,7 @@ xml_bind_yang_rpc_reply(clicon_handle h,
break;
}
if (yo != NULL){
xml_spec_set(xrpc, yo);
xml_spec_set(xrpc, yo);
/* Special case for ok and rpc-error */
if ((xc = xml_child_i_type(xrpc, 0, CX_ELMNT)) != NULL &&
(strcmp(xml_name(xc),"rpc-error") == 0
@ -920,7 +923,7 @@ xml_bind_special(cxobj *xd,
{
int retval = -1;
yang_stmt *yd;
if (yang_abs_schema_nodeid(yspec, schema_nodeid, &yd) < 0)
goto done;
if (yd)

View file

@ -88,7 +88,7 @@ changelog_rename(clicon_handle h,
int retval = -1;
xp_ctx *xctx = NULL;
char *str = NULL;
if (tag == NULL){
clicon_err(OE_XML, 0, "tag required");
goto done;
@ -160,7 +160,7 @@ changelog_insert(clicon_handle h,
{
int retval = -1;
cxobj *x;
if (xnew == NULL){
clicon_err(OE_XML, 0, "new required");
goto done;
@ -216,10 +216,12 @@ changelog_move(clicon_handle h,
}
/*! Perform a changelog operation
* @param[in] h Clicon handle
*
* @param[in] h Clixon handle
* @param[in] xt XML to upgrade
* @param[in] xi Changelog item
* @retval 0 OK
* @retval -1 Error
* @note XXX error handling!
* @note XXX xn --> xt xpath may not match
*/
@ -311,14 +313,17 @@ changelog_op(clicon_handle h,
return retval;
fail:
retval = 0;
clicon_debug(1, "%s fail op:%s ", __FUNCTION__, op);
clixon_debug(CLIXON_DBG_DEFAULT, "%s fail op:%s ", __FUNCTION__, op);
goto done;
}
/*! Iterate through one changelog item
* @param[in] h Clicon handle
*
* @param[in] h Clixon handle
* @param[in] xt Changelog list
* @param[in] xn XML to upgrade
* @retval 0 OK
* @retval -1 Error
*/
static int
changelog_iterate(clicon_handle h,
@ -331,7 +336,7 @@ changelog_iterate(clicon_handle h,
size_t veclen;
int ret;
int i;
if (xpath_vec(xch, NULL, "step", &vec, &veclen) < 0)
goto done;
/* Iterate through changelog items */
@ -343,7 +348,7 @@ changelog_iterate(clicon_handle h,
}
retval = 1;
done:
clicon_debug(1, "%s retval: %d", __FUNCTION__, retval);
clixon_debug(CLIXON_DBG_DEFAULT, "%s retval: %d", __FUNCTION__, retval);
if (vec)
free(vec);
return retval;
@ -353,7 +358,8 @@ changelog_iterate(clicon_handle h,
}
/*! Automatic upgrade using changelog
* @param[in] h Clicon handle
*
* @param[in] h Clixon handle
* @param[in] xt Top-level XML tree to be updated (includes other ns as well)
* @param[in] ns Namespace of module (for info)
* @param[in] op One of XML_FLAG_ADD, _DEL, _CHANGE
@ -367,13 +373,13 @@ changelog_iterate(clicon_handle h,
* @see upgrade_callback_register where this function should be registered
*/
int
xml_changelog_upgrade(clicon_handle h,
cxobj *xt,
xml_changelog_upgrade(clicon_handle h,
cxobj *xt,
char *ns,
uint16_t op,
uint32_t from,
uint32_t to,
void *arg,
void *arg,
cbuf *cbret)
{
int retval = -1;
@ -398,7 +404,7 @@ xml_changelog_upgrade(clicon_handle h,
* - find all changelogs in the interval: [from, to]
* - note it t=0 then no changelog is applied
*/
if (xpath_vec(xchlog, NULL, "changelog[namespace=\"%s\"]",
if (xpath_vec(xchlog, NULL, "changelog[namespace=\"%s\"]",
&vec, &veclen, ns) < 0)
goto done;
/* Get all changelogs in the interval [from,to]*/
@ -448,7 +454,7 @@ clixon_xml_changelog_init(clicon_handle h)
if ((fp = fopen(filename, "r")) == NULL){
clicon_err(OE_UNIX, errno, "fopen(%s)", filename);
goto done;
}
}
if (clixon_xml_parse_file(fp, YB_MODULE, yspec, &xt, NULL) < 0)
goto done;
if (xml_rootchild(xt, 0, &xt) < 0)
@ -466,7 +472,7 @@ clixon_xml_changelog_init(clicon_handle h)
goto done;
clicon_err(OE_YANG, 0, "validation failed: %s", cbuf_get(cbret));
goto done;
}
}
if (clicon_xml_changelog_set(h, xt) < 0)
goto done;
xt = NULL;
@ -485,11 +491,14 @@ clixon_xml_changelog_init(clicon_handle h)
}
/*! Given a top-level XML tree and a namespace, return a vector of matching XML nodes
* @param[in] h Clicon handle
*
* @param[in] h Clixon handle
* @param[in] xt Top-level XML tree, with children marked with namespaces
* @param[in] ns The namespace to select
* @param[out] vecp Vector containining XML nodes w namespace. Null-terminated.
* @param[out] veclenp Length of vector
* @retval 0 OK
* @retval -1 Error
* @note Need to free vec after use with free()
* Example
* xt ::= <config><a xmlns="urn:example:a"/><aaa xmlns="urn:example:a"/><a xmlns="urn:example:b"/></config
@ -524,7 +533,7 @@ xml_namespace_vec(clicon_handle h,
i = 0;
while ((xc = xml_child_each(xt, xc, CX_ELMNT)) != NULL) {
if (xml2ns(xc, NULL, &ns0) < 0) /* Get namespace of XML */
goto done;
goto done;
if (strcmp(ns, ns0))
continue; /* no match */
xvec[i++] = xc;

View file

@ -101,7 +101,7 @@ xml_default_create1(yang_stmt *y,
if (xml_prefix_set(xc, prefix) < 0)
goto done;
}
else{ /* Namespace does not exist in target, must add it w xmlns attr.
else{ /* Namespace does not exist in target, must add it w xmlns attr.
use source prefix */
if (xml_add_namespace(xc, xc, prefix, namespace) < 0)
goto done;
@ -124,7 +124,7 @@ xml_default_create1(yang_stmt *y,
* @param[in] xt XML tree
* @param[in] top Use default namespace (if you create xmlns statement)
* @retval 0 OK
* @retval -1 Error
* @retval -1 Error
*/
static int
xml_default_create(yang_stmt *y,
@ -136,7 +136,7 @@ xml_default_create(yang_stmt *y,
cxobj *xb;
char *str;
cg_var *cv;
if (xml_default_create1(y, xt, &xc) < 0)
goto done;
xml_flag_set(xc, XML_FLAG_DEFAULT);
@ -159,6 +159,7 @@ xml_default_create(yang_stmt *y,
}
/*! Traverse a choice
*
* From RFC7950 Sec 7.9.3
* 1. Default case, the default if no child nodes from any of the choice's cases exist
* 2. Default for child nodes under a case are only used if one of the nodes under that case
@ -177,7 +178,7 @@ xml_default_choice(yang_stmt *yc,
yang_stmt *yca = NULL;
yang_stmt *ydef;
clicon_debug(CLIXON_DBG_DETAIL, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DETAIL, "%s", __FUNCTION__);
/* 1. Is there a default case and no child under this choice?
*/
x = NULL;
@ -212,7 +213,7 @@ xml_default_choice(yang_stmt *yc,
* @param[in] state Set if global state, otherwise config
* @param[out] createp Need to create XML container
* @retval 0 OK
* @retval -1 Error
* @retval -1 Error
*/
static int
xml_nopresence_try(yang_stmt *yt,
@ -222,7 +223,7 @@ xml_nopresence_try(yang_stmt *yt,
int retval = -1;
yang_stmt *y;
yang_stmt *ydef;
if (yt == NULL || yang_keyword_get(yt) != Y_CONTAINER){
clicon_err(OE_XML, EINVAL, "yt argument is not container");
goto done;
@ -277,7 +278,7 @@ xml_nopresence_try(yang_stmt *yt,
* @param[in] xt XML tree (with yt as spec of xt, informally)
* @param[in] state Set if global state, otherwise config
* @retval 0 OK
* @retval -1 Error
* @retval -1 Error
* XXX If state, should not add config defaults
* if (state && yang_config(yc))
*/
@ -312,12 +313,12 @@ xml_default(yang_stmt *yt,
yc = NULL;
while ((yc = yn_each(yt, yc)) != NULL) {
/* If config parameter and local is config false */
if (!state && !yang_config(yc))
if (!state && !yang_config(yc))
continue;
switch (yang_keyword_get(yc)){
case Y_LEAF:
/* Want to add state defaults, but this is config */
if (state && yang_config_ancestor(yc))
if (state && yang_config_ancestor(yc))
break;
if ((cv = yang_cv_get(yc)) == NULL){
clicon_err(OE_YANG,0, "Internal error: yang leaf %s not populated with cv as it should",
@ -354,7 +355,7 @@ xml_default(yang_stmt *yt,
if (xml_nopresence_try(yc, state, &create) < 0)
goto done;
if (create){
/* Retval shows there is a default value need to create the
/* Retval shows there is a default value need to create the
* container */
if (xml_default_create1(yc, xt, &xc) < 0)
goto done;
@ -385,10 +386,11 @@ xml_default(yang_stmt *yt,
}
/*! Recursively fill in default values in an XML tree
*
* @param[in] xt XML tree
* @param[in] state If set expand defaults also for state data, otherwise only config
* @retval 0 OK
* @retval -1 Error
* @retval -1 Error
* @see xml_global_defaults
*/
int
@ -399,7 +401,7 @@ xml_default_recurse(cxobj *xn,
yang_stmt *yn;
cxobj *x;
yang_stmt *y;
if ((yn = (yang_stmt*)xml_spec(xn)) != NULL)
if (xml_default(yn, xn, state) < 0)
goto done;
@ -424,7 +426,7 @@ xml_default_recurse(cxobj *xn,
* @param[in] yspec Top-level YANG specification tree, all modules
* @param[in] state p Set if global state, otherwise config
* @retval 0 OK
* @retval -1 Error
* @retval -1 Error
*/
static int
xml_global_defaults_create(cxobj *xt,
@ -438,7 +440,7 @@ xml_global_defaults_create(cxobj *xt,
clicon_err(OE_XML, EINVAL, "yspec argument is not yang spec");
goto done;
}
while ((ymod = yn_each(yspec, ymod)) != NULL)
while ((ymod = yn_each(yspec, ymod)) != NULL)
if (xml_default(ymod, xt, state) < 0)
goto done;
retval = 0;
@ -455,7 +457,7 @@ xml_global_defaults_create(cxobj *xt,
* @param[in] yspec Top-level YANG specification tree, all modules
* @param[in] state Set if global state, otherwise config
* @retval 0 OK
* @retval -1 Error
* @retval -1 Error
* Uses cache?
* @see xml_default_recurse
*/
@ -478,7 +480,7 @@ xml_global_defaults(clicon_handle h,
cxobj *x0;
int ret;
char *key;
/* Use different keys for config and state */
key = state ? "global-defaults-state" : "global-defaults-config";
/* First get or compute global xml tree cache */
@ -553,7 +555,7 @@ xml_defaults_nopresence(cxobj *xn,
int ret;
enum rfc_6020 keyw;
int config = 1;
if ((yn = xml_spec(xn)) != NULL){
keyw = yang_keyword_get(yn);
if (keyw == Y_CONTAINER &&
@ -590,7 +592,7 @@ xml_defaults_nopresence(cxobj *xn,
}
else if (rmx)
/* May switch an empty non-presence container (rmx=1) to non-empty non-presence container (rmx=0) */
rmx = 0;
rmx = 0;
}
retval = rmx;
done:

View file

@ -65,7 +65,7 @@
#include "clixon_log.h"
#include "clixon_yang.h"
#include "clixon_xml.h"
#include "clixon_options.h"
#include "clixon_options.h"
#include "clixon_yang_module.h"
#include "clixon_xml_bind.h"
#include "clixon_xml_vec.h"
@ -78,7 +78,7 @@
* Constants
*/
/* Size of xml read buffer */
#define BUFLEN 1024
#define BUFLEN 1024
/*------------------------------------------------------------------------
* XML printing functions. Output a parse tree to file, string cligen buf
@ -101,9 +101,9 @@
*
*/
static int
xml2file_recurse(FILE *f,
cxobj *x,
int level,
xml2file_recurse(FILE *f,
cxobj *x,
int level,
int pretty,
char *prefix,
clicon_output_cb *fn,
@ -120,7 +120,7 @@ xml2file_recurse(FILE *f,
int exist = 0;
yang_stmt *y;
int level1;
if (x == NULL)
goto ok;
level1 = level*PRETTYPRINT_INDENT;
@ -179,7 +179,7 @@ xml2file_recurse(FILE *f,
/* Check for special case <a/> instead of <a></a>:
* Ie, no CX_BODY or CX_ELMNT child.
*/
if (hasbody==0 && haselement==0)
if (hasbody==0 && haselement==0)
(*fn)(f, "/>");
else{
(*fn)(f, ">");
@ -234,9 +234,9 @@ xml2file_recurse(FILE *f,
* for CLI calls, but not for others.
*/
int
clixon_xml2file(FILE *f,
cxobj *xn,
int level,
clixon_xml2file(FILE *f,
cxobj *xn,
int level,
int pretty,
char *prefix,
clicon_output_cb *fn,
@ -272,7 +272,7 @@ clixon_xml2file(FILE *f,
* @see clixon_xml2cbuf_cb print using a callback
*/
int
xml_print(FILE *f,
xml_print(FILE *f,
cxobj *x)
{
return xml2file_recurse(f, x, 0, 1, NULL, fprintf, 0);
@ -281,12 +281,12 @@ xml_print(FILE *f,
/*! Dump cxobj structure with pointers and flags for debugging, internal function
*/
static int
xml_dump1(FILE *f,
xml_dump1(FILE *f,
cxobj *x,
int indent)
{
cxobj *xc;
if (xml_type(x) != CX_ELMNT)
return 0;
fprintf(stderr, "%*s %s(%s)",
@ -309,7 +309,7 @@ xml_dump1(FILE *f,
}
return 0;
}
/*! Dump cxobj structure with pointers and flags for debugging
*
* @param[in] f UNIX output stream
@ -317,7 +317,7 @@ xml_dump1(FILE *f,
* @see xml_print
*/
int
xml_dump(FILE *f,
xml_dump(FILE *f,
cxobj *x)
{
return xml_dump1(f, x, 0);
@ -331,10 +331,12 @@ xml_dump(FILE *f,
* @param[in] pretty Insert \n and spaces to make the xml more readable.
* @param[in] prefix Add string to beginning of each line (if pretty)
* @param[in] depth Limit levels of child resources: -1 is all, 0 is none, 1 is node itself
* @retval 0 OK
* @retval -1 Error
*/
static int
clixon_xml2cbuf1(cbuf *cb,
cxobj *x,
clixon_xml2cbuf1(cbuf *cb,
cxobj *x,
int level,
int pretty,
char *prefix,
@ -348,7 +350,7 @@ clixon_xml2cbuf1(cbuf *cb,
char *namespace;
char *val;
int level1;
if (depth == 0)
goto ok;
level1 = level*PRETTYPRINT_INDENT;
@ -388,7 +390,7 @@ clixon_xml2cbuf1(cbuf *cb,
haselement = 0;
xc = NULL;
/* print attributes only */
while ((xc = xml_child_each(x, xc, -1)) != NULL)
while ((xc = xml_child_each(x, xc, -1)) != NULL)
switch (xml_type(xc)){
case CX_ATTR:
if (clixon_xml2cbuf1(cb, xc, level+1, pretty, prefix, -1) < 0)
@ -404,14 +406,14 @@ clixon_xml2cbuf1(cbuf *cb,
break;
}
/* Check for special case <a/> instead of <a></a> */
if (hasbody==0 && haselement==0)
if (hasbody==0 && haselement==0)
cbuf_append_str(cb, "/>");
else{
cbuf_append_str(cb, ">");
if (pretty && hasbody == 0)
cbuf_append_str(cb, "\n");
xc = NULL;
while ((xc = xml_child_each(x, xc, -1)) != NULL)
while ((xc = xml_child_each(x, xc, -1)) != NULL)
if (xml_type(xc) != CX_ATTR)
if (clixon_xml2cbuf1(cb, xc, level+1, pretty, prefix, depth-1) < 0)
goto done;
@ -472,7 +474,7 @@ clixon_xml2cbuf(cbuf *cb,
{
int retval = -1;
cxobj *xc;
if (skiptop){
xc = NULL;
while ((xc = xml_child_each(xn, xc, CX_ELMNT)) != NULL)
@ -489,12 +491,13 @@ clixon_xml2cbuf(cbuf *cb,
}
/*! Print actual xml tree datastructures (not xml), mainly for debugging
*
* @param[in,out] cb Cligen buffer to write to
* @param[in] xn Clicon xml tree
* @param[in] level Indentation level
*/
int
xmltree2cbuf(cbuf *cb,
xmltree2cbuf(cbuf *cb,
cxobj *x,
int level)
{
@ -517,7 +520,7 @@ xmltree2cbuf(cbuf *cb,
cprintf(cb, " {");
cprintf(cb, "\n");
xc = NULL;
while ((xc = xml_child_each(x, xc, -1)) != NULL)
while ((xc = xml_child_each(x, xc, -1)) != NULL)
xmltree2cbuf(cb, xc, level+1);
if (xml_child_nr(x)){
for (i=0; i<level*PRETTYPRINT_INDENT; i++)
@ -556,8 +559,8 @@ xmltree2cbuf(cbuf *cb,
* @note may be called recursively, some yang-bind (eg rpc) semantic checks may trigger error message
* @note yang-binding over schema mount-points do not work, you need to make a separate bind call
*/
static int
_xml_parse(const char *str,
static int
_xml_parse(const char *str,
yang_bind yb,
yang_stmt *yspec,
cxobj *xt,
@ -570,13 +573,13 @@ _xml_parse(const char *str,
int failed = 0; /* yang assignment */
int i;
clicon_debug(CLIXON_DBG_DETAIL, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DETAIL, "%s", __FUNCTION__);
if (strlen(str) == 0){
return 1; /* OK */
}
if (xt == NULL){
clicon_err(OE_XML, errno, "Unexpected NULL XML");
return -1;
return -1;
}
if ((xy.xy_parse_string = strdup(str)) == NULL){
clicon_err(OE_XML, errno, "strdup");
@ -586,7 +589,7 @@ _xml_parse(const char *str,
xy.xy_xparent = xt;
xy.xy_yspec = yspec;
if (clixon_xml_parsel_init(&xy) < 0)
goto done;
goto done;
if (clixon_xml_parseparse(&xy) != 0) /* yacc returns 1 on error */
goto done;
/* Purge all top-level body objects */
@ -599,7 +602,7 @@ _xml_parse(const char *str,
/* Verify namespaces after parsing */
if (xml2ns_recurse(x) < 0)
goto done;
/* Populate, ie associate xml nodes with yang specs
/* Populate, ie associate xml nodes with yang specs
*/
switch (yb){
case YB_NONE:
@ -654,7 +657,7 @@ _xml_parse(const char *str,
free(xy.xy_parse_string);
if (xy.xy_xvec)
free(xy.xy_xvec);
return retval;
return retval;
fail: /* invalid */
retval = 0;
goto done;
@ -686,8 +689,8 @@ _xml_parse(const char *str,
* @note, If xt empty, a top-level symbol will be added so that <tree../> will be: <top><tree.../></tree></top>
* @note May block on file I/O
*/
int
clixon_xml_parse_file(FILE *fp,
int
clixon_xml_parse_file(FILE *fp,
yang_bind yb,
yang_stmt *yspec,
cxobj **xt,
@ -783,8 +786,8 @@ clixon_xml_parse_file(FILE *fp,
* @note You need to free the xml parse tree after use, using xml_free()
* @note If empty on entry, a new TOP xml will be created named "top"
*/
int
clixon_xml_parse_string(const char *str,
int
clixon_xml_parse_string(const char *str,
yang_bind yb,
yang_stmt *yspec,
cxobj **xt,
@ -808,7 +811,6 @@ clixon_xml_parse_string(const char *str,
/*! Read XML from var-arg list and parse it into xml tree
*
* Utility function using stdarg instead of static string.
* @param[in] yb How to bind yang to XML top-level when parsing
* @param[in] yspec Yang specification, or NULL
* @param[in,out] xtop Top of XML parse tree. If it is NULL, top element
@ -829,9 +831,9 @@ clixon_xml_parse_string(const char *str,
* @see clixon_xml_parse_file
* @note If vararg list is empty, consider using clixon_xml_parse_string()
*/
int
int
clixon_xml_parse_va(yang_bind yb,
yang_stmt *yspec,
yang_stmt *yspec,
cxobj **xtop,
cxobj **xerr,
const char *format, ...)
@ -852,7 +854,7 @@ clixon_xml_parse_va(yang_bind yb,
va_start(args, format);
len = vsnprintf(str, len, format, args) + 1;
va_end(args);
retval = clixon_xml_parse_string(str, yb, yspec, xtop, xerr);
retval = clixon_xml_parse_string(str, yb, yspec, xtop, xerr);
done:
if (str)
free(str);
@ -860,6 +862,7 @@ clixon_xml_parse_va(yang_bind yb,
}
/*! Copy an attribute value(eg message-id) from one xml (eg rpc input) to another xml (eg rpc outgoing)
*
* @param[in] xin Get attr value from this XML
* @param[in] xout Set attr value to this XML
* @param[in] name Attribute name
@ -912,7 +915,7 @@ xml_diff_keys(cbuf *cb,
cvk = yang_cvec_get(y); /* Use Y_LIST cache, see ys_populate_list() */
cvi = NULL;
while ((cvi = cvec_each(cvk, cvi)) != NULL) {
keyname = cv_string_get(cvi);
keyname = cv_string_get(cvi);
keyval = xml_find_body(x, keyname);
cprintf(cb, "%*s<%s>%s</%s>\n", level, "", keyname, keyval, keyname);
}
@ -930,7 +933,7 @@ xml_diff_context(cbuf *cb,
int retval = -1;
char *prefix;
char *namespace = NULL;
prefix = xml_prefix(xn);
if (xml2ns(xn, prefix, &namespace) < 0)
goto done;
@ -973,7 +976,7 @@ xml_diff_context(cbuf *cb,
*/
int
xml_diff2cbuf(cbuf *cb,
cxobj *x0,
cxobj *x0,
cxobj *x1,
int level,
int skiptop)
@ -993,7 +996,7 @@ xml_diff2cbuf(cbuf *cb,
level1 = level*PRETTYPRINT_INDENT;
y0 = xml_spec(x0);
/* Traverse x0 and x1 in lock-step */
x0c = x1c = NULL;
x0c = x1c = NULL;
x0c = xml_child_each(x0, x0c, CX_ELMNT);
x1c = xml_child_each(x1, x1c, CX_ELMNT);
for (;;){
@ -1117,7 +1120,7 @@ xml_diff2cbuf(cbuf *cb,
*/
int
clixon_xml_diff2cbuf(cbuf *cb,
cxobj *x0,
cxobj *x0,
cxobj *x1)
{
return xml_diff2cbuf(cb, x0, x1, 0, 1);

View file

@ -110,6 +110,7 @@ isxmlns(cxobj *x)
}
/*! Translate a single xml node to a cligen variable vector. Note not recursive
*
* @param[in] xt XML tree containing one top node
* @param[in] ys Yang spec containing type specification of top-node of xt
* @param[out] cvv CLIgen variable vector. Should be freed by cvec_free()
@ -132,8 +133,8 @@ isxmlns(cxobj *x)
* @see cvec2xml
*/
int
xml2cvec(cxobj *xt,
yang_stmt *yt,
xml2cvec(cxobj *xt,
yang_stmt *yt,
cvec **cvv0)
{
int retval = -1;
@ -158,7 +159,7 @@ xml2cvec(cxobj *xt,
while ((xc = xml_child_each(xt, xc, CX_ELMNT)) != NULL){
name = xml_name(xc);
if ((ys = yang_find_datanode(yt, name)) == NULL){
clicon_debug(0, "%s: yang sanity problem: %s in xml but not present in yang under %s",
clixon_debug(0, "%s: yang sanity problem: %s in xml but not present in yang under %s",
__FUNCTION__, name, yang_argument_get(yt));
if ((body = xml_body(xc)) != NULL){
if ((cv = cv_new(CGV_STRING)) == NULL){
@ -172,7 +173,7 @@ xml2cvec(cxobj *xt,
}
/* If value is out-of-range, log and skip value, and continue */
if (ret == 0){
clicon_log(LOG_WARNING, "cv_parse %s: %s", name, reason);
clicon_log(LOG_WARNING, "cv_parse %s: %s", name, reason);
if (reason)
free(reason);
}
@ -206,8 +207,8 @@ xml2cvec(cxobj *xt,
}
}
}
if (clicon_debug_get() > 1){
clicon_debug(CLIXON_DBG_DETAIL, "%s cvv:\n", __FUNCTION__);
if (clixon_debug_get() > 1){
clixon_debug(CLIXON_DBG_DETAIL, "%s cvv:\n", __FUNCTION__);
cvec_print(stderr, cvv);
}
*cvv0 = cvv;
@ -219,6 +220,7 @@ xml2cvec(cxobj *xt,
}
/*! Translate a cligen variable vector to an XML tree with depth one
*
* @param[in] cvv CLIgen variable vector. Should be freed by cvec_free()
* @param[in] toptag The XML tree in xt will have this XML tag
* @param[in] xt Parent, or NULL
@ -229,8 +231,8 @@ xml2cvec(cxobj *xt,
* @see cvec2xml This does more but has an internal xml2cvec translation
*/
int
cvec2xml_1(cvec *cvv,
char *toptag,
cvec2xml_1(cvec *cvv,
char *toptag,
cxobj *xp,
cxobj **xt0)
{
@ -244,7 +246,7 @@ cvec2xml_1(cvec *cvv,
int i;
cv = NULL;
while ((cv = cvec_each(cvv, cv)) != NULL)
while ((cv = cvec_each(cvv, cv)) != NULL)
len++;
if ((xt = xml_new(toptag, xp, CX_ELMNT)) == NULL)
goto err;
@ -275,6 +277,7 @@ cvec2xml_1(cvec *cvv,
}
/*! Recursive help function to compute differences between two xml trees
*
* @param[in] x0 First XML tree
* @param[in] x1 Second XML tree
* @param[out] x0vec Pointervector to XML nodes existing in only first tree
@ -284,6 +287,8 @@ cvec2xml_1(cvec *cvv,
* @param[out] changed_x0 Pointervector to XML nodes changed orig value
* @param[out] changed_x1 Pointervector to XML nodes changed wanted value
* @param[out] changedlen Length of changed vector
* @retval 0 Ok
* @retval -1 Error
* Algorithm to compare two sorted lists A, B:
* A 0 1 2 3 5 6
* B 0 2 4 5 6
@ -299,7 +304,7 @@ cvec2xml_1(cvec *cvv,
* @see xml_diff API function, this one is internal and recursive
*/
static int
xml_diff1(cxobj *x0,
xml_diff1(cxobj *x0,
cxobj *x1,
cxobj ***x0vec,
int *x0veclen,
@ -319,20 +324,20 @@ xml_diff1(cxobj *x0,
int eq;
/* Traverse x0 and x1 in lock-step */
x0c = x1c = NULL;
x0c = x1c = NULL;
x0c = xml_child_each(x0, x0c, CX_ELMNT);
x1c = xml_child_each(x1, x1c, CX_ELMNT);
for (;;){
if (x0c == NULL && x1c == NULL)
goto ok;
else if (x0c == NULL){
if (cxvec_append(x1c, x1vec, x1veclen) < 0)
if (cxvec_append(x1c, x1vec, x1veclen) < 0)
goto done;
x1c = xml_child_each(x1, x1c, CX_ELMNT);
continue;
}
else if (x1c == NULL){
if (cxvec_append(x0c, x0vec, x0veclen) < 0)
if (cxvec_append(x0c, x0vec, x0veclen) < 0)
goto done;
x0c = xml_child_each(x0, x0c, CX_ELMNT);
continue;
@ -340,13 +345,13 @@ xml_diff1(cxobj *x0,
/* Both x0c and x1c exists, check if they are yang-equal. */
eq = xml_cmp(x0c, x1c, 0, 0, NULL);
if (eq < 0){
if (cxvec_append(x0c, x0vec, x0veclen) < 0)
if (cxvec_append(x0c, x0vec, x0veclen) < 0)
goto done;
x0c = xml_child_each(x0, x0c, CX_ELMNT);
continue;
}
else if (eq > 0){
if (cxvec_append(x1c, x1vec, x1veclen) < 0)
if (cxvec_append(x1c, x1vec, x1veclen) < 0)
goto done;
x1c = xml_child_each(x1, x1c, CX_ELMNT);
continue;
@ -358,9 +363,9 @@ xml_diff1(cxobj *x0,
yc0 = xml_spec(x0c);
yc1 = xml_spec(x1c);
if (yc0 && yc1 && yc0 != yc1){ /* choice */
if (cxvec_append(x0c, x0vec, x0veclen) < 0)
if (cxvec_append(x0c, x0vec, x0veclen) < 0)
goto done;
if (cxvec_append(x1c, x1vec, x1veclen) < 0)
if (cxvec_append(x1c, x1vec, x1veclen) < 0)
goto done;
}
else
@ -371,18 +376,18 @@ xml_diff1(cxobj *x0,
if (b0 == NULL && b1 == NULL)
;
else if (b0 == NULL || b1 == NULL
|| strcmp(b0, b1) != 0
|| strcmp(b0, b1) != 0
){
if (cxvec_append(x0c, changed_x0, changedlen) < 0)
if (cxvec_append(x0c, changed_x0, changedlen) < 0)
goto done;
(*changedlen)--; /* append two vectors */
if (cxvec_append(x1c, changed_x1, changedlen) < 0)
if (cxvec_append(x1c, changed_x1, changedlen) < 0)
goto done;
}
}
else if (xml_diff1(x0c, x1c,
x0vec, x0veclen,
x1vec, x1veclen,
else if (xml_diff1(x0c, x1c,
x0vec, x0veclen,
x1vec, x1veclen,
changed_x0, changed_x1, changedlen)< 0)
goto done;
}
@ -413,7 +418,7 @@ xml_diff1(cxobj *x0,
* @see clixon_xml_diff_print same algorithm but print in +/- diff format
*/
int
xml_diff(cxobj *x0,
xml_diff(cxobj *x0,
cxobj *x1,
cxobj ***first,
int *firstlen,
@ -426,23 +431,23 @@ xml_diff(cxobj *x0,
int retval = -1;
*firstlen = 0;
*secondlen = 0;
*secondlen = 0;
*changedlen = 0;
if (x0 == NULL && x1 == NULL)
return 0;
if (x1 == NULL){
if (cxvec_append(x0, first, firstlen) < 0)
if (cxvec_append(x0, first, firstlen) < 0)
goto done;
goto ok;
}
if (x0 == NULL){
if (cxvec_append(x0, second, secondlen) < 0)
if (cxvec_append(x0, second, secondlen) < 0)
goto done;
goto ok;
}
if (xml_diff1(x0, x1,
first, firstlen,
second, secondlen,
first, firstlen,
second, secondlen,
changed_x0, changed_x1, changedlen) < 0)
goto done;
ok:
@ -460,7 +465,7 @@ xml_diff(cxobj *x0,
* @see xml_diff which returns diff sets
*/
int
xml_tree_equal(cxobj *x0,
xml_tree_equal(cxobj *x0,
cxobj *x1)
{
int retval = 1; /* Not equal */
@ -471,9 +476,9 @@ xml_tree_equal(cxobj *x0,
char *b1;
cxobj *x0c = NULL; /* x0 child */
cxobj *x1c = NULL; /* x1 child */
/* Traverse x0 and x1 in lock-step */
x0c = x1c = NULL;
x0c = x1c = NULL;
x0c = xml_child_each(x0, x0c, CX_ELMNT);
x1c = xml_child_each(x1, x1c, CX_ELMNT);
for (;;){
@ -510,7 +515,7 @@ xml_tree_equal(cxobj *x0,
if (b0 == NULL && b1 == NULL)
;
else if (b0 == NULL || b1 == NULL
|| strcmp(b0, b1) != 0
|| strcmp(b0, b1) != 0
){
goto done;
}
@ -536,6 +541,8 @@ xml_tree_equal(cxobj *x0,
* @param[in] flag Which flag to test for
* @param[in] test 1: test that flag is set, 0: test that flag is not set
* @param[out] upmark Set if a child (recursively) has marked set.
* @retval 0 OK
* @retval -1 Error
* The function removes all branches that does not pass the test
* Purge all nodes that dont have MARK flag set recursively.
* Save all nodes that is MARK:ed or have at least one (grand*)child that is MARKed
@ -546,7 +553,7 @@ xml_tree_equal(cxobj *x0,
* @see xml_tree_prune_flagged for a simpler variant
*/
int
xml_tree_prune_flagged_sub(cxobj *xt,
xml_tree_prune_flagged_sub(cxobj *xt,
int flag,
int test,
int *upmark)
@ -607,7 +614,7 @@ xml_tree_prune_flagged_sub(cxobj *xt,
goto done;
x = xprev;
}
xprev = x;
xprev = x;
}
}
retval = 0;
@ -618,16 +625,19 @@ xml_tree_prune_flagged_sub(cxobj *xt,
}
/*! Prune everything that passes test
*
* @param[in] xt XML tree with some node marked
* @param[in] flag Which flag to test for
* @param[in] test 1: test that flag is set, 0: test that flag is not set
* @retval 0 OK
* @retval -1 Error
* The function removes all branches that does not pass test
* @code
* xml_tree_prune_flagged(xt, XML_FLAG_MARK, 1);
* @endcode
*/
int
xml_tree_prune_flagged(cxobj *xt,
xml_tree_prune_flagged(cxobj *xt,
int flag,
int test)
{
@ -642,7 +652,7 @@ xml_tree_prune_flagged(cxobj *xt,
if (xml_purge(x) < 0)
goto done;
x = xprev;
continue;
continue;
}
if (xml_tree_prune_flagged(x, flag, test) < 0)
goto done;
@ -654,9 +664,12 @@ xml_tree_prune_flagged(cxobj *xt,
}
/*! Prune everything that passes test
*
* @param[in] xt XML tree with some node marked
* @param[in] flags Flags set
* @param[in] mask Which flags to test for
* @retval 0 OK
* @retval -1 Error
* The function removes all branches that does pass test
* @code
* xml_tree_prune_flags(xt, XML_FLAG_MARK, XML_FLAG_MARK|XML_FLAG_DEFAULT);
@ -699,9 +712,9 @@ xml_tree_prune_flags(cxobj *xt,
* @param -1 Error
*/
int
xml_namespace_change(cxobj *x,
char *ns,
char *prefix)
xml_namespace_change(cxobj *x,
char *ns,
char *prefix)
{
int retval = -1;
char *ns0 = NULL; /* existing namespace */
@ -712,7 +725,7 @@ xml_namespace_change(cxobj *x,
if (xml2ns(x, xml_prefix(x), &ns0) < 0)
goto done;
if (ns0 && strcmp(ns0, ns) == 0)
goto ok; /* Already has right namespace */
goto ok; /* Already has right namespace */
/* Is namespace already declared? */
if (xml2prefix(x, ns, &prefix0) == 1){
/* Yes it is declared and the prefix is prefix0 */
@ -728,7 +741,7 @@ xml_namespace_change(cxobj *x,
else
xp = xml_parent(x);
if (xml_add_namespace(x, xp, prefix, ns) < 0)
goto done;
goto done;
/* Add prefix to x, if any */
if (prefix && xml_prefix_set(x, prefix) < 0)
goto done;
@ -740,10 +753,15 @@ xml_namespace_change(cxobj *x,
}
/*! Sanitize an xml tree: xml node has matching yang_stmt pointer
* @param[in] xt XML top of tree
*
* @param[in] xt XML top of tree
* @param[in] arg Not used
* @retval 0 OK
* @retval -1 Error
*/
int
xml_sanity(cxobj *xt,
xml_sanity(cxobj *xt,
void *arg)
{
int retval = -1;
@ -756,7 +774,7 @@ xml_sanity(cxobj *xt,
}
name = xml_name(xt);
if (strstr(yang_argument_get(ys), name)==NULL){
clicon_err(OE_XML, 0, "xml node name '%s' does not match yang spec arg '%s'",
clicon_err(OE_XML, 0, "xml node name '%s' does not match yang spec arg '%s'",
name, yang_argument_get(ys));
goto done;
}
@ -766,23 +784,24 @@ xml_sanity(cxobj *xt,
}
/*! Detect state data: Either mark or break on first occurence and return xerror
*
* @param[in] xt XML tree
* @param[out] xerr If set return netconf error, abort and return if a state variable found
* @retval -1 Error
* @retval 0 Status node found and return xerror
* @retval 1 OK
* @retval 0 Status node found and return xerror
* @retval -1 Error
* Note that the behaviour is quite different if xerr is set or not,...
*/
int
xml_non_config_data(cxobj *xt,
cxobj **xerr)
xml_non_config_data(cxobj *xt,
cxobj **xerr)
{
int retval = -1;
cxobj *x;
yang_stmt *y;
int ret;
cbuf *cb = NULL;
x = NULL;
while ((x = xml_child_each(xt, x, CX_ELMNT)) != NULL) {
if ((y = (yang_stmt*)xml_spec(x)) == NULL)
@ -817,7 +836,10 @@ xml_non_config_data(cxobj *xt,
}
/*! Check if the module tree x is in is assigned right XML namespace, assign if not
*
* @param[in] x XML node
* @retval 0 OK
* @retval -1 Error
*(0. You should probably find the XML root and apply this function to that.)
* 1. Check which namespace x should have (via yang). This is correct namespace.
* 2. Check which namespace x has via its XML tree
@ -862,10 +884,11 @@ xmlns_assign(cxobj *x)
}
/*! Given a src element node x0 and a target node x1, assign (optional) prefix and namespace
*
* @param[in] x1 XML tree
* @param[in] x1p XML tree parent
* @retval 0 OK
* @retval -1 OK
* @retval -1 Error
* @see assign_namespace_element this is a subroutine
*/
static int
@ -880,7 +903,7 @@ assign_namespace(cxobj *x1, /* target */
char *pexist = NULL;
cvec *nsc0 = NULL;
cvec *nsc = NULL;
/* 2a. Detect if namespace is declared in x1 target parent */
if (xml2prefix(x1p, ns, &pexist) == 1){
/* Yes, and it has prefix pexist */
@ -920,7 +943,7 @@ assign_namespace(cxobj *x1, /* target */
}
goto ok; /* skip */
}
else { /* namespace does not exist in target x1,
else { /* namespace does not exist in target x1,
*/
if (isroot){
if (prefix0 && (prefix1 = strdup(prefix0)) == NULL){
@ -929,7 +952,7 @@ assign_namespace(cxobj *x1, /* target */
}
}
else{
if (prefix0 == NULL){ /* Use default namespace, may break use of previous default
if (prefix0 == NULL){ /* Use default namespace, may break use of previous default
* somewhere in x1
*/
prefix1 = NULL;
@ -939,7 +962,7 @@ assign_namespace(cxobj *x1, /* target */
if (xml_add_namespace(x1, x1, prefix1, ns) < 0)
goto done;
if (prefix1 && xml_prefix_set(x1, prefix1) < 0)
goto done;
goto done;
}
ok:
/* 6. Ensure x1 cache is updated (I think it is done w xmlns_set above) */
@ -951,11 +974,12 @@ assign_namespace(cxobj *x1, /* target */
}
/*! Given a src element node x0 and a target node x1, assign (optional) prefix and namespace
*
* @param[in] x0 Source XML tree
* @param[in] x1 Target XML tree
* @param[in] x1p Target XML tree parent
* @retval 0 OK
* @retval -1 OK
* @retval -1 Error
* 1. Find N=namespace(x0)
* 2. Detect if N is declared in x1 parent
* 3. If yes, assign prefix to x1
@ -975,7 +999,7 @@ assign_namespace_element(cxobj *x0, /* source */
char *namespace = NULL;
char *prefix0 = NULL;;
int isroot;
isroot = xml_parent(x1p)==NULL &&
xml_flag(x1p, XML_FLAG_TOP) &&
xml_prefix(x1p)==NULL;
@ -1007,6 +1031,8 @@ assign_namespace_element(cxobj *x0, /* source */
*
* @param[in] x0 Source XML
* @param[in] x1 Destination XML
* @retval 0 OK
* @retval -1 Error
* @note "standard" namespaces, including clixon internal namespaces are removed
*/
int
@ -1017,10 +1043,10 @@ assign_namespace_body(cxobj *x0, /* source */
char *namespace = NULL;
char *namespace1;
char *name;
char *prefix0;
char *prefix1 = NULL;
char *prefix0;
char *prefix1 = NULL;
cxobj *xa;
xa = NULL;
while ((xa = xml_child_each_attr(x0, xa)) != NULL) {
prefix0 = xml_prefix(xa);
@ -1058,6 +1084,7 @@ assign_namespace_body(cxobj *x0, /* source */
}
/*! Merge a base tree x0 with x1 with yang spec y
*
* @param[in] x0 Base xml tree (can be NULL in add scenarios)
* @param[in] y0 Yang spec corresponding to xml-node x0. NULL if x0 is NULL
* @param[in] x0p Parent of x0
@ -1092,7 +1119,7 @@ xml_merge1(cxobj *x0, /* the target */
char *ns;
char *px;
char *pxe;
if (x1 == NULL || xml_type(x1) != CX_ELMNT || y0 == NULL){
clicon_err(OE_XML, EINVAL, "x1 is NULL or not XML element, or lacks yang spec");
goto done;
@ -1131,13 +1158,13 @@ xml_merge1(cxobj *x0, /* the target */
if (x1bstr){
if ((x0b = xml_body_get(x0)) == NULL){
if ((x0b = xml_new("body", x0, CX_BODY)) == NULL)
goto done;
goto done;
}
if (xml_value_set(x0b, x1bstr) < 0)
goto done;
}
if (xml_parent(x0) == NULL &&
xml_insert(x0p, x0, INS_LAST, NULL, NULL) < 0)
xml_insert(x0p, x0, INS_LAST, NULL, NULL) < 0)
goto done;
if (assign_namespace_element(x1, x0, x0p) < 0)
goto done;
@ -1200,7 +1227,7 @@ xml_merge1(cxobj *x0, /* the target */
goto fail;
}
if (xml_parent(x0) == NULL &&
xml_insert(x0p, x0, INS_LAST, NULL, NULL) < 0)
xml_insert(x0p, x0, INS_LAST, NULL, NULL) < 0)
goto done;
} /* else Y_CONTAINER */
ok:
@ -1219,6 +1246,7 @@ xml_merge1(cxobj *x0, /* the target */
}
/*! Merge XML trees x1 into x0 according to yang spec yspec
*
* @param[in] x0 Base xml tree (can be NULL in add scenarios)
* @param[in] x1 xml tree which modifies base
* @param[in] yspec Yang spec
@ -1268,7 +1296,7 @@ xml_merge(cxobj *x0,
clicon_err(OE_UNIX, errno, "strdup");
goto done;
}
goto fail;
goto fail;
}
/* Get yang spec of the child */
if ((yc = yang_find_datanode(ymod, x1cname)) == NULL){
@ -1331,6 +1359,8 @@ xml_merge(cxobj *x0,
* @param[in] ytype YANG type noden
* @param[in] valstr Integer string value
* @param[out] enumstr Value of enum, dont free
* @retval 0 OK
* @retval -1 Error
*/
int
yang_valstr2enum(yang_stmt *ytype,
@ -1365,7 +1395,7 @@ yang_valstr2enum(yang_stmt *ytype,
* @param[out] valstr Corresponding string containing an int (direct pointer, dont free)
* @retval 1 OK, result in valstr
* @retval 0 Invalid, not found
* @retval -1 Error
* @retval -1 Error
*/
int
yang_enum2valstr(yang_stmt *ytype,
@ -1373,8 +1403,8 @@ yang_enum2valstr(yang_stmt *ytype,
char **valstr)
{
int retval = -1;
yang_stmt *yenum;
yang_stmt *yval;
yang_stmt *yenum;
yang_stmt *yval;
if (valstr == NULL){
clicon_err(OE_UNIX, EINVAL, "valstr is NULL");
@ -1395,6 +1425,7 @@ yang_enum2valstr(yang_stmt *ytype,
}
/*! Get integer value from xml node from yang enumeration
*
* @param[in] node XML node in a tree
* @param[out] val Integer value returned
* @retval 0 OK, value parsed
@ -1408,7 +1439,7 @@ yang_enum2valstr(yang_stmt *ytype,
* Thanks: Matthew Smith
*/
int
yang_enum_int_value(cxobj *node,
yang_enum_int_value(cxobj *node,
int32_t *val)
{
int retval = -1;
@ -1427,7 +1458,7 @@ yang_enum_int_value(cxobj *node,
goto done;
if ((ytype = yang_find(ys, Y_TYPE, NULL)) == NULL)
goto done;
if (yang_type_resolve(ys, ys, ytype, &yrestype,
if (yang_type_resolve(ys, ys, ytype, &yrestype,
NULL, NULL, NULL, NULL, NULL) < 0)
goto done;
if (yrestype == NULL){
@ -1447,17 +1478,21 @@ done:
}
/*! Given XML tree x0 with marked nodes, copy marked nodes to new tree x1
* Two marks are used: XML_FLAG_MARK and XML_FLAG_CHANGE
*
* Two marks are used: XML_FLAG_MARK and XML_FLAG_CHANGE
* The algorithm works as following:
* (1) Copy individual nodes marked with XML_FLAG_CHANGE
* until nodes marked with XML_FLAG_MARK are reached, where
* (2) the complete subtree of that node is copied.
* (3) Special case: key nodes in lists are copied if any node in list is marked
* @param[in] x0
* @param[in] x1
* @retval 0 OK
* @retval -1 Error
* @note you may want to check:!yang_config(ys)
*/
int
xml_copy_marked(cxobj *x0,
xml_copy_marked(cxobj *x0,
cxobj *x1)
{
int retval = -1;
@ -1476,14 +1511,13 @@ xml_copy_marked(cxobj *x0,
if ((prefix = xml_prefix(x0)) != NULL)
if (xml_prefix_set(x1, prefix) < 0)
goto done;
/* Copy all attributes */
x = NULL;
while ((x = xml_child_each_attr(x0, x)) != NULL) {
name = xml_name(x);
if ((xcopy = xml_new(name, x1, CX_ATTR)) == NULL)
goto done;
if (xml_copy(x, xcopy) < 0)
if (xml_copy(x, xcopy) < 0)
goto done;
}
@ -1506,9 +1540,9 @@ xml_copy_marked(cxobj *x0,
/* (2) the complete subtree of that node is copied. */
if ((xcopy = xml_new(name, x1, CX_ELMNT)) == NULL)
goto done;
if (xml_copy(x, xcopy) < 0)
if (xml_copy(x, xcopy) < 0)
goto done;
continue;
continue;
}
if (xml_flag(x, XML_FLAG_CHANGE)){
/* Copy individual nodes marked with XML_FLAG_CHANGE */
@ -1526,7 +1560,7 @@ xml_copy_marked(cxobj *x0,
if (iskey){
if ((xcopy = xml_new(name, x1, CX_ELMNT)) == NULL)
goto done;
if (xml_copy(x, xcopy) < 0)
if (xml_copy(x, xcopy) < 0)
goto done;
}
}
@ -1545,7 +1579,7 @@ xml_copy_marked(cxobj *x0,
* @param[out] nrp 1: when stmt evaluates to true
* @param[out] xpathp when stmts xpath
* @retval 0 OK
* @retval -1 Error
* @retval -1 Error
* First variants of WHEN: Augmented and uses when using special info in node
* Second variant of when, actual "when" sub-node RFC 7950 Sec 7.21.5. Can only be one.
*/
@ -1659,7 +1693,7 @@ yang_xml_mandatory(cxobj *xt,
}
/* 3) A container node without a "presence" statement and that has at
* least one mandatory node as a child. */
else if (keyw == Y_CONTAINER &&
else if (keyw == Y_CONTAINER &&
yang_find(ys, Y_PRESENCE, NULL) == NULL){
yc = NULL;
while ((yc = yn_each(ys, yc)) != NULL) {
@ -1680,6 +1714,7 @@ yang_xml_mandatory(cxobj *xt,
}
/*! Is XML node (ie under <rpc>) an action, ie name action and belong to YANG_XML_NAMESPACE?
*
* @param[in] xn XML node
* @retval 1 Yes, an action
* @retval 0 No, not an action
@ -1706,6 +1741,7 @@ xml_rpc_isaction(cxobj *xn)
}
/*! Find innermost node under <action> carrying the name of the defined action
*
* Find innermost container or list contains an XML element
* that carries the name of the defined action.
* @param[in] xn XML node
@ -1744,12 +1780,15 @@ xml_find_action(cxobj *xn,
}
/*! Utility function: recursive traverse an XML tree and remove nodes based on attribute value
*
* Conditionally remove attribute and node
* @param[in] xn XML node
* @param[in] ns Namespace of attribute
* @param[in] name Attribute name
* @param[in] value Attribute value
* @param[in] keepnode 0: remove node associated with attribute; 1: keep node but remove attr
* @retval 0 OK
* @retval -1 Error
*/
int
purge_tagged_nodes(cxobj *xn,
@ -1797,6 +1836,8 @@ purge_tagged_nodes(cxobj *xn,
* @param[in] xc1 XML tree 1
* @param[in] xc2 XML tree 2
* @param[in] format "text"|"xml"|"json"|"cli"|"netconf" (see format_enum)
* @retval 0 OK
* @retval -1 Error
* @see clixon_xml_diff2cbuf with better XML in-mem comparison but is YANG dependent
*/
int

View file

@ -79,13 +79,13 @@
* See rfc6241 3.1: urn:ietf:params:xml:ns:netconf:base:1.0.
*/
static int _USE_NAMESPACE_NETCONF_DEFAULT = 0;
/*! Set if use internal default namespace mechanism or not
*
* This function shouldnt really be here, it sets a local variable from the value of the
* option CLICON_NAMESPACE_NETCONF_DEFAULT, but the code where it is used is deep in the call
* stack and cannot get the clicon handle currently.
* @param[in] h Clicon handle
* @param[in] h Clixon handle
*/
int
xml_nsctx_namespace_netconf_default(clicon_handle h)
@ -155,7 +155,7 @@ xml_nsctx_get(cvec *cvv,
char *prefix)
{
cg_var *cv;
if ((cv = cvec_find(cvv, prefix)) != NULL)
return cv_string_get(cv);
return NULL;
@ -206,7 +206,7 @@ xml_nsctx_add(cvec *cvv,
{
int retval = -1;
cg_var *cv;
if ((cv = cvec_find(cvv, prefix)) != NULL) /* found, replace that */
cv_string_set(cv, ns);
else /* cvec exists, but not prefix */
@ -289,7 +289,7 @@ xml_nsctx_node(cxobj *xn,
{
int retval = -1;
cvec *nc = NULL;
if ((nc = cvec_new(0)) == NULL){
clicon_err(OE_XML, errno, "cvec_new");
goto done;
@ -339,7 +339,7 @@ xml_nsctx_yang(yang_stmt *yn,
char *prefix;
char *mynamespace;
char *myprefix;
if (yang_keyword_get(yn) == Y_SPEC){
clicon_err(OE_YANG, EINVAL, "yang spec node is invalid argument");
goto done;
@ -376,7 +376,7 @@ xml_nsctx_yang(yang_stmt *yn,
if ((name = yang_argument_get(y)) == NULL)
continue; /* Just skip - shouldnt happen) */
if ((yp = yang_find(y, Y_PREFIX, NULL)) == NULL)
continue;
continue;
if ((prefix = yang_argument_get(yp)) == NULL)
continue;
if ((ym = yang_find(yspec, Y_MODULE, name)) == NULL)
@ -470,7 +470,7 @@ xml_nsctx_cbuf(cbuf *cb,
{
cg_var *cv = NULL;
char *prefix;
while ((cv = cvec_each(nsc, cv)) != NULL){
cprintf(cb, " xmlns");
if ((prefix = cv_name_get(cv)))
@ -493,7 +493,7 @@ xml_nsctx_cbuf(cbuf *cb,
* err;
* @endcode
* @see xmlns_set cache is set
* @note, this function uses a cache.
* @note, this function uses a cache.
*/
int
xml2ns(cxobj *x,
@ -503,7 +503,7 @@ xml2ns(cxobj *x,
int retval = -1;
char *ns = NULL;
cxobj *xp;
if ((ns = nscache_get(x, prefix)) != NULL)
goto ok;
if (prefix != NULL) /* xmlns:<prefix>="<uri>" */
@ -526,7 +526,7 @@ xml2ns(cxobj *x,
}
}
/* Set default namespace cache (since code is at this point,
* no cache was found
* no cache was found
* If not, this is devastating when populating deep yang structures
*/
if (ns &&
@ -564,7 +564,7 @@ xml2ns_recurse(cxobj *xt)
if (namespace == NULL){
clicon_err(OE_XML, ENOENT, "No namespace associated with %s:%s", prefix, xml_name(x));
goto done;
}
}
}
if (xml2ns_recurse(x) < 0)
goto done;
@ -618,6 +618,8 @@ xmlns_set(cxobj *x,
* Check if already there
* @param[in] x XML tree
* @param[in] nsc Namespace context
* @retval 0 OK
* @retval -1 Error
* @note you need to do an xml_sort(x) after the call
*/
int
@ -676,7 +678,7 @@ xml2prefix(cxobj *xn,
xa = NULL;
while ((xa = xml_child_each_attr(xn, xa)) != NULL) {
/* xmlns=namespace */
if (strcmp("xmlns", xml_name(xa)) == 0){
if (strcmp("xmlns", xml_name(xa)) == 0){
if (strcmp(xml_value(xa), namespace) == 0){
if (nscache_set(xn, NULL, namespace) < 0)
goto done;
@ -686,7 +688,7 @@ xml2prefix(cxobj *xn,
}
/* xmlns:prefix=namespace */
else if ((xaprefix=xml_prefix(xa)) != NULL &&
strcmp("xmlns", xaprefix) == 0){
strcmp("xmlns", xaprefix) == 0){
if (strcmp(xml_value(xa), namespace) == 0){
prefix = xml_name(xa);
if (nscache_set(xn, prefix, namespace) < 0)
@ -720,6 +722,8 @@ xml2prefix(cxobj *xn,
* @param[in] xp XML node where namespace attribute should be declared (can be same)
* @param[in] prefix1 Use this prefix
* @param[in] namespace Use this namespace
* @retval 0 OK
* @retval -1 Error
* @note x and xp must be different if x is an attribute and may be different otherwise
*/
int
@ -730,7 +734,7 @@ xml_add_namespace(cxobj *x,
{
int retval = -1;
cxobj *xa = NULL;
/* Add binding to x1p. We add to parent due to heurestics, so we dont
* end up in adding it to large number of siblings
*/

View file

@ -68,7 +68,7 @@
#define YY_NO_INPUT
/* typecast macro */
#define _XY ((clixon_xml_yacc *)_xy)
#define _XY ((clixon_xml_yacc *)_xy)
#undef clixon_xml_parsewrap
int clixon_xml_parsewrap(void)
@ -120,7 +120,7 @@ ncname {namestart}{namechar}*
<START>"/>" { BEGIN(STATEA); return ESLASH; }
<START>"<!--" { BEGIN(CMNT); return BCOMMENT; }
<START>"</" return BSLASH;
<START>[/=] return *clixon_xml_parsetext;
<START>[/=] return *clixon_xml_parsetext;
<START>\< return *clixon_xml_parsetext;
<START>\> { BEGIN(STATEA); return *clixon_xml_parsetext; }
<START>\" { _XY->xy_lex_state=START;BEGIN(STRDQ); return *clixon_xml_parsetext; }
@ -155,10 +155,10 @@ ncname {namestart}{namechar}*
<CDATA>[^]\n]+ { clixon_xml_parselval.string = yytext; return CHARDATA;}
<CMNT>"-->" { BEGIN(START); return ECOMMENT; }
<CMNT>.
<CMNT>.
<TEXTDECL>encoding return ENC;
<TEXTDECL>version return VER;
<TEXTDECL>standalone return SD;
<TEXTDECL>version return VER;
<TEXTDECL>standalone return SD;
<TEXTDECL>"=" { return *clixon_xml_parsetext; }
<TEXTDECL>"?>" { BEGIN(START);return EQMARK;}
<TEXTDECL>\" { _XY->xy_lex_state =TEXTDECL;BEGIN(STRDQ); return *clixon_xml_parsetext; }

View file

@ -50,9 +50,9 @@
%token VER ENC SD
%token BSLASH ESLASH
%token BXMLDCL BQMARK EQMARK
%token BCOMMENT ECOMMENT
%token BCOMMENT ECOMMENT
%type <string> attvalue
%type <string> attvalue
%lex-param {void *_xy} /* Add this argument to parse() and lex() function */
%parse-param {void *_xy}
@ -86,48 +86,52 @@
/* Enable for debugging, steals some cycles otherwise */
#if 0
#define _PARSE_DEBUG(s) clicon_debug(1,(s))
#define _PARSE_DEBUG(s) clixon_debug(1,(s))
#else
#define _PARSE_DEBUG(s)
#endif
void
void
clixon_xml_parseerror(void *_xy,
char *s)
{
clicon_err(OE_XML, XMLPARSE_ERRNO, "xml_parse: line %d: %s: at or before: %s",
char *s)
{
clicon_err(OE_XML, XMLPARSE_ERRNO, "xml_parse: line %d: %s: at or before: %s",
_XY->xy_linenum,
s,
clixon_xml_parsetext);
clixon_xml_parsetext);
return;
}
/*! Parse XML content, eg chars between >...<
*
* @param[in] xy
* @param[in] encoded set if ampersand encoded
* @param[in] str Body string, direct pointer (copy before use, dont free)
* Note that we dont handle escaped characters correctly
* @param[in] str Body string, direct pointer (copy before use, dont free)
* @retval 0 OK
* @retval -1 Error
* Note that we dont handle escaped characters correctly
* there may also be some leakage here on NULL return
*/
static int
xml_parse_content(clixon_xml_yacc *xy,
xml_parse_content(clixon_xml_yacc *xy,
int encoded,
char *str)
{
int retval = -1;
cxobj *xn = xy->xy_xelement;
cxobj *xp = xy->xy_xparent;
int retval = -1;
xy->xy_xelement = NULL; /* init */
if (xn == NULL){
if ((xn = xml_new("body", xp, CX_BODY)) == NULL)
goto done;
goto done;
}
if (encoded)
if (xml_value_append(xn, "&") < 0)
goto done;
goto done;
if (xml_value_append(xn, str) < 0)
goto done;
goto done;
xy->xy_xelement = xn;
retval = 0;
done:
@ -135,16 +139,19 @@ xml_parse_content(clixon_xml_yacc *xy,
}
/*! Add whitespace
*
* If text, ie only body, keep as is.
* But if there is an element, then skip all whitespace.
* @retval 0 OK
* @retval -1 Error
*/
static int
xml_parse_whitespace(clixon_xml_yacc *xy,
char *str)
{
int retval = -1;
cxobj *xn = xy->xy_xelement;
cxobj *xp = xy->xy_xparent;
int retval = -1;
int i;
xy->xy_xelement = NULL; /* init */
@ -160,17 +167,17 @@ xml_parse_whitespace(clixon_xml_yacc *xy,
}
if (xn == NULL){
if ((xn = xml_new("body", xp, CX_BODY)) == NULL)
goto done;
goto done;
}
if (xml_value_append(xn, str) < 0)
goto done;
goto done;
xy->xy_xelement = xn;
ok:
retval = 0;
done:
return retval;
}
static int
xml_parse_version(clixon_xml_yacc *xy,
char *ver)
@ -186,6 +193,7 @@ xml_parse_version(clixon_xml_yacc *xy,
}
/*! Parse XML encoding
*
* From under Encoding Declaration:
* In an encoding declaration, the values UTF-8, UTF-16, ISO-10646-UCS-2, and ISO-10646-UCS-4
* SHOULD be used for the various encodings and transformations of Unicode / ISO/IEC 10646, the
@ -209,13 +217,15 @@ xml_parse_encoding(clixon_xml_yacc *xy,
}
return 0;
}
/*! Parse Qualified name -> (Un)PrefixedName
*
* This is where all (parsed) xml elements are created
* @param[in] xy XML parser yacc handler struct
* @param[in] prefix Prefix, namespace, or NULL
* @param[in] localpart Name
* @retval 0 OK
* @retval -1 Error
*/
static int
xml_parse_prefixed_name(clixon_xml_yacc *xy,
@ -224,10 +234,10 @@ xml_parse_prefixed_name(clixon_xml_yacc *xy,
{
int retval = -1;
cxobj *x;
cxobj *xp; /* xml parent */
cxobj *xp; /* xml parent */
xp = xy->xy_xparent;
if ((x = xml_new(name, xp, CX_ELMNT)) == NULL)
if ((x = xml_new(name, xp, CX_ELMNT)) == NULL)
goto done;
/* Cant check namespaces here since local xmlns attributes loaded after */
if (xml_prefix_set(x, prefix) < 0)
@ -282,9 +292,11 @@ xml_parse_endslash_post(clixon_xml_yacc *xy)
* @param[in] xy XML parser yacc handler struct
* @param[in] prefix
* @param[in] name
* @retval 0 OK
* @retval -1 Error
*/
static int
xml_parse_bslash(clixon_xml_yacc *xy,
xml_parse_bslash(clixon_xml_yacc *xy,
char *prefix,
char *name)
{
@ -298,9 +310,9 @@ xml_parse_bslash(clixon_xml_yacc *xy,
prefix0 = xml_prefix(x);
name0 = xml_name(x);
/* Check name or prerix unequal from begin-tag */
if (clicon_strcmp(name0, name) ||
clicon_strcmp(prefix0, prefix)){
clicon_err(OE_XML, XMLPARSE_ERRNO, "Sanity check failed: %s%s%s vs %s%s%s",
if (clicon_strcmp(name0, name) ||
clicon_strcmp(prefix0, prefix)){
clicon_err(OE_XML, XMLPARSE_ERRNO, "Sanity check failed: %s%s%s vs %s%s%s",
prefix0?prefix0:"", prefix0?":":"", name0,
prefix?prefix:"", prefix?":":"", name);
goto done;
@ -314,7 +326,7 @@ xml_parse_bslash(clixon_xml_yacc *xy,
* be stripped, see xml_bind_yang()
*/
xc = NULL;
while ((xc = xml_child_each(x, xc, CX_ELMNT)) != NULL)
while ((xc = xml_child_each(x, xc, CX_ELMNT)) != NULL)
break;
if (xc != NULL){ /* at least one element */
if (xml_rm_children(x, CX_BODY) < 0) /* remove all bodies */
@ -330,9 +342,12 @@ xml_parse_bslash(clixon_xml_yacc *xy,
}
/*! Parse XML attribute
*
* Special cases:
* - DefaultAttName: xmlns
* - PrefixedAttName: xmlns:NAME
* - PrefixedAttName: xmlns:NAME
* @retval 0 OK
* @retval -1 Error
*/
static int
xml_parse_attr(clixon_xml_yacc *xy,
@ -341,7 +356,7 @@ xml_parse_attr(clixon_xml_yacc *xy,
char *attval)
{
int retval = -1;
cxobj *xa = NULL;
cxobj *xa = NULL;
if ((xa = xml_find_type(xy->xy_xelement, prefix, name, CX_ATTR)) == NULL){
if ((xa = xml_new(name, xy->xy_xelement, CX_ATTR)) == NULL)
@ -361,12 +376,12 @@ xml_parse_attr(clixon_xml_yacc *xy,
return retval;
}
%}
%}
%%
/* [1] document ::= prolog element Misc* */
document : prolog element misclist MY_EOF
{ _PARSE_DEBUG("document->prolog element misc* ACCEPT");
{ _PARSE_DEBUG("document->prolog element misc* ACCEPT");
YYACCEPT; }
| elist MY_EOF
{ _PARSE_DEBUG("document->elist ACCEPT"); /* internal exception*/
@ -394,10 +409,10 @@ xmldcl : BXMLDCL verinfo encodingdecl sddecl EQMARK
{ _PARSE_DEBUG("xmldcl->verinfo encodingdecl? sddecl?"); }
;
verinfo : VER '=' '\"' STRING '\"'
verinfo : VER '=' '\"' STRING '\"'
{ if (xml_parse_version(_XY, $4) <0) YYABORT;
_PARSE_DEBUG("verinfo->version=\"STRING\"");}
| VER '=' '\'' STRING '\''
| VER '=' '\'' STRING '\''
{ if (xml_parse_version(_XY, $4) <0) YYABORT;
_PARSE_DEBUG("verinfo->version='STRING'");}
;
@ -416,30 +431,30 @@ sddecl : SD '=' '\"' STRING '\"' {if ($4)free($4);}
|
;
/* [39] element ::= EmptyElemTag | STag content ETag */
element : '<' qname attrs element1
element : '<' qname attrs element1
{ _PARSE_DEBUG("element -> < qname attrs element1"); }
;
qname : NAME { if (xml_parse_prefixed_name(_XY, NULL, $1) < 0) YYABORT;
qname : NAME { if (xml_parse_prefixed_name(_XY, NULL, $1) < 0) YYABORT;
_PARSE_DEBUG("qname -> NAME");}
| NAME ':' NAME { if (xml_parse_prefixed_name(_XY, $1, $3) < 0) YYABORT;
| NAME ':' NAME { if (xml_parse_prefixed_name(_XY, $1, $3) < 0) YYABORT;
_PARSE_DEBUG("qname -> NAME : NAME");}
;
element1 : ESLASH {_XY->xy_xelement = NULL;
_PARSE_DEBUG("element1 -> />");}
element1 : ESLASH {_XY->xy_xelement = NULL;
_PARSE_DEBUG("element1 -> />");}
| '>' { xml_parse_endslash_pre(_XY); }
elist { xml_parse_endslash_mid(_XY); }
endtag { xml_parse_endslash_post(_XY);
_PARSE_DEBUG("element1 -> > elist endtag");}
endtag { xml_parse_endslash_post(_XY);
_PARSE_DEBUG("element1 -> > elist endtag");}
;
endtag : BSLASH NAME '>'
endtag : BSLASH NAME '>'
{ _PARSE_DEBUG("endtag -> < </ NAME>");
if (xml_parse_bslash(_XY, NULL, $2) < 0) YYABORT; }
| BSLASH NAME ':' NAME '>'
{ if (xml_parse_bslash(_XY, $2, $4) < 0) YYABORT;
| BSLASH NAME ':' NAME '>'
{ if (xml_parse_bslash(_XY, $2, $4) < 0) YYABORT;
_PARSE_DEBUG("endtag -> < </ NAME:NAME >"); }
;
@ -451,11 +466,11 @@ elist : elist content { _PARSE_DEBUG("elist -> elist content"); }
content : element { _PARSE_DEBUG("content -> element"); }
| comment { _PARSE_DEBUG("content -> comment"); }
| pi { _PARSE_DEBUG("content -> pi"); }
| CHARDATA { if (xml_parse_content(_XY, 0, $1) < 0) YYABORT;
| CHARDATA { if (xml_parse_content(_XY, 0, $1) < 0) YYABORT;
_PARSE_DEBUG("content -> CHARDATA"); }
| ENCODED { if (xml_parse_content(_XY, 1, $1) < 0) YYABORT;
| ENCODED { if (xml_parse_content(_XY, 1, $1) < 0) YYABORT;
_PARSE_DEBUG("content -> ENCODED"); }
| WHITESPACE { if (xml_parse_whitespace(_XY, $1) < 0) YYABORT;
| WHITESPACE { if (xml_parse_whitespace(_XY, $1) < 0) YYABORT;
_PARSE_DEBUG("content -> WHITESPACE"); }
| { _PARSE_DEBUG("content -> "); }
;

View file

@ -74,6 +74,7 @@
#include "clixon_xml_sort.h"
/*! Get xml body value as cligen variable
*
* @param[in] x XML node (body and leaf/leaf-list)
* @param[out] cvp Pointer to cligen variable containing value of x body
* @retval 0 OK, cvp contains cv or NULL
@ -97,7 +98,7 @@ xml_cv_cache(cxobj *x,
int options = 0;
uint8_t fraction = 0;
char *body;
if ((body = xml_body(x)) == NULL)
body="";
if ((cv = xml_cv(x)) != NULL)
@ -120,7 +121,6 @@ xml_cv_cache(cxobj *x,
}
if (cvtype == CGV_DEC64)
cv_dec64_n_set(cv, fraction);
if ((ret = cv_parse1(body, cv, &reason)) < 0){
clicon_err(OE_YANG, errno, "cv_parse1");
goto done;
@ -158,6 +158,7 @@ xml_cv_cache_clear(cxobj *xt)
}
/*! Help function to qsort for sorting entries in xml child vector same parent
*
* @param[in] x1 object 1
* @param[in] x2 object 2
* @param[in] same If set, x1 and x2 are member of same parent & enumeration
@ -212,7 +213,7 @@ xml_cmp(cxobj *x1,
char *b1;
char *b2;
char *keyname;
cg_var *cv1 = NULL;
cg_var *cv1 = NULL;
cg_var *cv2 = NULL;
int nr1 = 0;
int nr2 = 0;
@ -254,7 +255,7 @@ xml_cmp(cxobj *x1,
equal = 1;
goto done;
}
if (y1 != y2){
if (y1 != y2){
/* XXX handle errors */
yi1 = yang_order(y1);
yi2 = yang_order(y2);
@ -384,26 +385,28 @@ xml_cmp(cxobj *x1,
break;
} /* switch */
done:
clicon_debug(CLIXON_DBG_EXTRA, "%s %s %s eq:%d nr: %d %d yi: %d %d", __FUNCTION__, xml_name(x1), xml_name(x2), equal, nr1, nr2, yi1, yi2);
clixon_debug(CLIXON_DBG_EXTRA, "%s %s %s eq:%d nr: %d %d yi: %d %d", __FUNCTION__, xml_name(x1), xml_name(x2), equal, nr1, nr2, yi1, yi2);
return equal;
}
/*!
/*! Sort xml
*
* @note args are pointer to pointers, to fit into qsort cmp function
*/
static int
xml_cmp_qsort(const void* arg1,
xml_cmp_qsort(const void* arg1,
const void* arg2)
{
return xml_cmp(*(struct xml**)arg1, *(struct xml**)arg2, 1, 0, NULL);
}
/*! Sort children of an XML node
*
* Assume populated by yang spec.
* @param[in] x0 XML node
* @retval -1 Error, aborted at first error encounter
* @retval 0 OK, all nodes traversed (subparts may have been skipped)
* @retval 1 OK, aborted on first fn returned 1
* @retval 0 OK, all nodes traversed (subparts may have been skipped)
* @retval -1 Error, aborted at first error encounter
* @see xml_apply - typically called by recursive apply function
* @see xml_sort_verify
*/
@ -412,7 +415,7 @@ xml_sort(cxobj *x)
{
#ifndef STATE_ORDERED_BY_SYSTEM
yang_stmt *ys;
/* Abort sort if non-config (=state) data */
if ((ys = xml_spec(x)) != 0 && yang_config(ys)==0)
return 1;
@ -423,7 +426,11 @@ xml_sort(cxobj *x)
}
/*! Recursively sort a tree
*
* Alt to use xml_apply
* @param[in] xn XML node
* @retval 0 OK
* @retval -1 Error
*/
int
xml_sort_recurse(cxobj *xn)
@ -431,7 +438,7 @@ xml_sort_recurse(cxobj *xn)
int retval = -1;
cxobj *x;
int ret;
ret = xml_sort_verify(xn, NULL);
if (ret == 1) /* This node is not sortable */
goto ok;
@ -478,7 +485,7 @@ xml_find_keys_notsorted(cxobj *xp,
cxobj *xc;
yang_stmt *yc;
int yi;
for (i=mid+1; i<xml_child_nr(xp); i++){ /* First increment */
xc = xml_child_i(xp, i);
yc = xml_spec(xc);
@ -512,6 +519,7 @@ xml_find_keys_notsorted(cxobj *xp,
}
/*! Find more equal objects in a vector up and down in the array of the present
*
* @param[in] childvec Vector of children of parent
* @param[in] childlen Length of child vector
* @param[in] x1 XML node to match
@ -535,7 +543,7 @@ search_multi_equals(cxobj **childvec,
cxobj *xc;
yang_stmt *yc;
int yi;
for (i=mid-1; i>=0; i--){ /* First decrement */
xc = childvec[i];
yc = xml_spec(xc);
@ -581,7 +589,7 @@ search_multi_equals_xvec(clixon_xvec *childvec,
cxobj *xc;
yang_stmt *yc;
int yi;
for (i=mid-1; i>=0; i--){ /* First decrement */
xc = clixon_xvec_i(childvec, i);
yc = xml_spec(xc);
@ -612,6 +620,7 @@ search_multi_equals_xvec(clixon_xvec *childvec,
}
/*! Insert xi in vector sorted according to index variable xi
*
* @param[in] x1 XML parent object (the list element)
* @param[in] ivec Sorted index vector
* @param[in] low Lower range limit
@ -627,7 +636,7 @@ int
xml_search_indexvar_binary_pos(cxobj *x1,
char *indexvar,
clixon_xvec *ivec,
int low,
int low,
int upper,
int max,
int *eq)
@ -636,9 +645,9 @@ xml_search_indexvar_binary_pos(cxobj *x1,
int mid;
int cmp;
cxobj *xc;
if (upper < low){ /* beyond range */
clicon_err(OE_XML, 0, "low>upper %d %d", low, upper);
clicon_err(OE_XML, 0, "low>upper %d %d", low, upper);
goto done;
}
if (low == upper){
@ -647,7 +656,7 @@ xml_search_indexvar_binary_pos(cxobj *x1,
}
mid = (low + upper) / 2;
if (mid >= max){ /* beyond range */
clicon_err(OE_XML, 0, "Beyond range %d %d %d", low, mid, upper);
clicon_err(OE_XML, 0, "Beyond range %d %d %d", low, mid, upper);
goto done;
}
xc = clixon_xvec_i(ivec, mid);
@ -666,14 +675,14 @@ xml_search_indexvar_binary_pos(cxobj *x1,
if (eq) /* No exact match */
*eq = 0;
if (cmp < 0) /* return either 0 if cmp<0 or +1 if cmp>0 */
retval = mid;
retval = mid;
else
retval = mid+1;
retval = mid+1;
goto done;
}
if (cmp < 0)
return xml_search_indexvar_binary_pos(x1, indexvar, ivec, low, mid, max, eq);
else
else
return xml_search_indexvar_binary_pos(x1, indexvar, ivec, mid+1, upper, max, eq);
}
done:
@ -684,7 +693,7 @@ static int
xml_search_indexvar(cxobj *xp,
cxobj *x1,
int yangi,
int low,
int low,
int upper,
char *indexvar,
clixon_xvec *xvec)
@ -722,6 +731,7 @@ xml_search_indexvar(cxobj *xp,
#endif /* XML_EXPLICIT_INDEX */
/*! Find XML child under xp matching x1 using binary search
*
* @param[in] xp Parent xml node.
* @param[in] x1 Find this object among xp:s children
* @param[in] sorted If x1 is ordered by user or statedata, the list is not sorted
@ -739,7 +749,7 @@ xml_search_binary(cxobj *xp,
cxobj *x1,
int sorted,
int yangi,
int low,
int low,
int upper,
int skip1,
char *indexvar,
@ -789,7 +799,7 @@ xml_search_binary(cxobj *xp,
}
else if (cmp < 0)
xml_search_binary(xp, x1, sorted, yangi, low, mid-1, skip1, indexvar, xvec);
else
else
xml_search_binary(xp, x1, sorted, yangi, mid+1, upper, skip1, indexvar, xvec);
ok:
retval = 0;
@ -827,7 +837,7 @@ xml_search_yang(cxobj *xp,
int upper = xml_child_nr(xp);
int sorted = 1;
int yangi;
if (xp == NULL){
clicon_err(OE_XML, EINVAL, "xp is NULL");
goto done;
@ -856,6 +866,7 @@ xml_search_yang(cxobj *xp,
}
/*! Insert xn in xp:s sorted child list (special case of ordered-by user)
*
* @param[in] xp Parent xml node. If NULL just remove from old parent.
* @param[in] xn Child xml node to insert under xp
* @param[in] yn Yang stmt of xml child node
@ -920,22 +931,22 @@ xml_insert_userorder(cxobj *xp,
switch (yang_keyword_get(yn)){
case Y_LEAF_LIST:
if ((xc = xpath_first(xp, nsc_key, "%s[.='%s']", xml_name(xn), key_val)) == NULL)
clicon_err(OE_YANG, 0, "bad-attribute: value, missing-instance: %s", key_val);
clicon_err(OE_YANG, 0, "bad-attribute: value, missing-instance: %s", key_val);
else {
if ((i = xml_child_order(xp, xc)) < 0)
clicon_err(OE_YANG, 0, "internal error xpath found but not in child list");
else
retval = (ins==INS_BEFORE)?i:i+1;
retval = (ins==INS_BEFORE)?i:i+1;
}
break;
case Y_LIST:
if ((xc = xpath_first(xp, nsc_key, "%s%s", xml_name(xn), key_val)) == NULL)
clicon_err(OE_YANG, 0, "bad-attribute: key, missing-instance: %s", key_val);
clicon_err(OE_YANG, 0, "bad-attribute: key, missing-instance: %s", key_val);
else {
if ((i = xml_child_order(xp, xc)) < 0)
clicon_err(OE_YANG, 0, "internal error xpath found but not in child list");
else
retval = (ins==INS_BEFORE)?i:i+1;
retval = (ins==INS_BEFORE)?i:i+1;
}
break;
default:
@ -949,6 +960,7 @@ xml_insert_userorder(cxobj *xp,
}
/*! Insert xn in xp:s sorted child list
*
* Find a point in xp childvec with two adjacent nodes xi,xi+1 such that
* xi<=xn<=xi+1 or xn<=x0 or xmax<=xn
* @param[in] xp Parent xml node. If NULL just remove from old parent.
@ -973,7 +985,7 @@ xml_insert2(cxobj *xp,
enum insert_type ins,
char *key_val,
cvec *nsc_key,
int low,
int low,
int upper)
{
int retval = -1;
@ -982,9 +994,9 @@ xml_insert2(cxobj *xp,
cxobj *xc;
yang_stmt *yc;
int yi;
if (low > upper){ /* beyond range */
clicon_err(OE_XML, 0, "low>upper %d %d", low, upper);
clicon_err(OE_XML, 0, "low>upper %d %d", low, upper);
goto done;
}
if (low == upper){
@ -993,7 +1005,7 @@ xml_insert2(cxobj *xp,
}
mid = (low + upper) / 2;
if (mid >= xml_child_nr(xp)){ /* beyond range */
clicon_err(OE_XML, 0, "Beyond range %d %d %d", low, mid, upper);
clicon_err(OE_XML, 0, "Beyond range %d %d %d", low, mid, upper);
goto done;
}
xc = xml_child_i(xp, mid);
@ -1002,7 +1014,7 @@ xml_insert2(cxobj *xp,
clicon_err(OE_XML, 0, "No spec found %s (wrong xml type:%s)",
xml_name(xc), xml_type2str(xml_type(xc)));
else
clicon_err(OE_XML, 0, "No spec found %s", xml_name(xc));
clicon_err(OE_XML, 0, "No spec found %s", xml_name(xc));
goto done;
}
if (yc == yn){ /* Same yang */
@ -1017,7 +1029,7 @@ xml_insert2(cxobj *xp,
if ((yi = yang_order(yc)) < -1)
goto done;
cmp = yni - yi;
/* One case is a choice where
/* One case is a choice where
* xc = <tcp/>, xn = <udp/>
* same order but different yang spec
*/
@ -1036,13 +1048,14 @@ xml_insert2(cxobj *xp,
}
else if (cmp < 0)
return xml_insert2(xp, xn, yn, yni, userorder, ins, key_val, nsc_key, low, mid);
else
else
return xml_insert2(xp, xn, yn, yni, userorder, ins, key_val, nsc_key, mid+1, upper);
done:
return retval;
}
/*! Insert xc as child to xp in sorted place. Remove xc from previous parent.
*
* @param[in] xp Parent xml node. If NULL just remove from old parent.
* @param[in] x Child xml node to insert under xp
* @param[in] ins Insert operation (if ordered-by user)
@ -1112,6 +1125,7 @@ xml_insert(cxobj *xp,
}
/*! Verify all children of XML node are sorted according to xml_sort()
*
* @param[in] x XML node. Check its children
* @param[in] arg Dummy. Ensures xml_apply can be used with this fn
* @retval 1 Not sortable
@ -1128,7 +1142,7 @@ xml_sort_verify(cxobj *x0,
cxobj *xprev = NULL;
#ifndef STATE_ORDERED_BY_SYSTEM
yang_stmt *ys;
/* Abort sort if non-config (=state) data */
if ((ys = xml_spec(x0)) != 0 && yang_config_ancestor(ys)==0){
retval = 1;
@ -1151,6 +1165,7 @@ xml_sort_verify(cxobj *x0,
}
/*! Given child tree x1c, find (first) matching child in base tree x0 and return as x0cp
*
* @param[in] x0 Base tree node
* @param[in] x1c Modification tree child
* @param[in] yc Yang spec of tree child. If null revert to linear search.
@ -1161,7 +1176,7 @@ xml_sort_verify(cxobj *x0,
* @see xml_cmp regarding what "match" means in this context (model-match not value-match)
*/
int
match_base_child(cxobj *x0,
match_base_child(cxobj *x0,
cxobj *x1c,
yang_stmt *yc,
cxobj **x0cp)
@ -1172,10 +1187,10 @@ match_base_child(cxobj *x0,
cxobj *xb;
char *keyname;
clixon_xvec *xvec = NULL;
*x0cp = NULL; /* init return value */
/* Revert to simple xml lookup if no yang */
if (yc == NULL){
if (yc == NULL){
*x0cp = xml_find(x0, xml_name(x1c));
goto ok;
}
@ -1189,7 +1204,7 @@ match_base_child(cxobj *x0,
break;
case Y_LIST: /* Match with key values */
cvk = yang_cvec_get(yc); /* Use Y_LIST cache, see ys_populate_list() */
cvi = NULL;
cvi = NULL;
while ((cvi = cvec_each(cvk, cvi)) != NULL) {
keyname = cv_string_get(cvi);
if ((xb = xml_find(x1c, keyname)) == NULL)
@ -1271,6 +1286,7 @@ xml_find_noyang_cvk(char *ns0,
}
/*! API for search in XML child list with no yang available
*
* Fallback if no yang available. Only linear search for matching name, and eventual index match
*/
static int
@ -1323,7 +1339,7 @@ xml_find_noyang_name(cxobj *xp,
* linear seacrh
* - if yes, then construct a dummy search object and find it in the list of xp:s children
* using binary search
* @param[in] xp Parent xml node.
* @param[in] xp Parent xml node.
* @param[in] yc Yang spec of list child (preferred) See rule (2) above
* @param[in] cvk List of keys and values as CLIgen vector on the form k1=foo, k2=bar
* @param[out] xvec Array of found nodes
@ -1440,9 +1456,9 @@ xml_find_index_yang(cxobj *xp,
while ((xk = xml_child_each(xc, xk, CX_ELMNT)) != NULL) {
if ((yk = yang_find(yc, Y_LEAF, xml_name(xk))) == NULL){
clicon_err(OE_YANG, ENOENT, "yang spec of key %s not found", xml_name(xk));
goto done;
goto done;
}
if (xml_spec_set(xk, yk) < 0)
if (xml_spec_set(xk, yk) < 0)
goto done;
}
if (xml_search_yang(xp, xc, yc, 1, indexvar, xvec) < 0)
@ -1522,7 +1538,7 @@ clixon_xml_find_index(cxobj *xp,
int retval = -1;
int ret;
yang_stmt *yc = NULL;
if (xvec == NULL){
clicon_err(OE_YANG, EINVAL, "xvec");
goto done;
@ -1542,7 +1558,7 @@ clixon_xml_find_index(cxobj *xp,
if (yc){
if ((ret = xml_find_index_yang(xp, yc, cvk, xvec)) < 0)
goto done;
if (ret == 0){ /* This means yang method did not work for some reason
if (ret == 0){ /* This means yang method did not work for some reason
* such as not being list key indexes in cvk, for example
*/
if (xml_find_noyang_name(xp, ns, name, cvk, xvec) < 0)
@ -1560,7 +1576,7 @@ clixon_xml_find_index(cxobj *xp,
/*! Find positional parameter in xml child list, eg x/y[42]. Note, not optimized
*
* Create a temporary search object: a list (xc) with a key (xk) and call the binary search.
* @param[in] xp Parent xml node.
* @param[in] xp Parent xml node.
* @param[in] yc Yang spec of list child
* @param[in] pos Position
* @param[out] xvec Array of found nodes

View file

@ -71,15 +71,16 @@
#define XVEC_MAX_THRESHOLD 1024 /* exponential growth to here, then linear */
/*! Clixon xml vector concrete implementaion of the abstract clixon_xvec type
*
* Contiguous vector (not linked list) so that binary search can be done by direct index access
*/
struct clixon_xml_vec {
cxobj **xv_vec; /* Sorted vector of xml object pointers */
int xv_len; /* Length of vector */
int xv_max; /* Vector allocation */
int xv_max; /* Vector allocation */
};
/*! Increment cxobj vector in an XML object vector
/*! Increment cxobj vector in an XML object vector
*
* Exponential growth to a threshold, then linear
* @param[in] xv XML tree vector
@ -90,7 +91,7 @@ static int
clixon_xvec_inc(clixon_xvec *xv)
{
int retval = -1;
xv->xv_len++;
if (xv->xv_len > xv->xv_max){
if (xv->xv_max < XVEC_MAX_DEFAULT)
@ -173,6 +174,7 @@ clixon_xvec_free(clixon_xvec *xv)
}
/*! Return length of XML object list
*
* @param[in] xv XML tree vector
* @retval len Length of XML object vector
*/
@ -183,6 +185,7 @@ clixon_xvec_len(clixon_xvec *xv)
}
/*! Return i:th XML object in XML object vector
*
* @param[in] xv XML tree vector
* @retval x OK
* @retval NULL Not found
@ -214,7 +217,7 @@ clixon_xvec_extract(clixon_xvec *xv,
int *xmax)
{
int retval = -1;
if (xv == NULL){
clicon_err(OE_XML, EINVAL, "xv is NULL");
goto done;
@ -248,7 +251,6 @@ clixon_xvec_extract(clixon_xvec *xv,
int
clixon_xvec_append(clixon_xvec *xv,
cxobj *x)
{
int retval = -1;
@ -332,7 +334,7 @@ clixon_xvec_insert_pos(clixon_xvec *xv,
{
int retval = -1;
size_t size;
if (clixon_xvec_inc(xv) < 0)
goto done;
size = (xv->xv_len - i -1)*sizeof(cxobj *);
@ -355,7 +357,7 @@ clixon_xvec_rm_pos(clixon_xvec *xv,
int i)
{
size_t size;
size = (xv->xv_len - i + 1)*sizeof(cxobj *);
memmove(&xv->xv_vec[i], &xv->xv_vec[i+1], size);
xv->xv_len--;
@ -367,14 +369,14 @@ clixon_xvec_rm_pos(clixon_xvec *xv,
* @param[in] f UNIX output stream
* @param[in] xv XML tree vector
* @retval 0 OK
* @retval -1 Error
* @retval -1 Error
*/
int
clixon_xvec_print(FILE *f,
clixon_xvec *xv)
{
int i;
for (i=0; i<xv->xv_len; i++)
if (clixon_xml2file(f, xv->xv_vec[i], 0, 1, NULL, fprintf, 0, 0) < 0)
return -1;

View file

@ -32,7 +32,7 @@
***** END LICENSE BLOCK *****
* Clixon XML XPATH 1.0 according to https://www.w3.org/TR/xpath-10
* Clixon XML XPath 1.0 according to https://www.w3.org/TR/xpath-10
*
* Note on xcur parameter to most xpath functions:
* The W3 standard defines the document root / element as the top-level.
@ -158,7 +158,7 @@ static const map_str2int axis_type_map[] = {
/*
* XPATH parse tree type
* XPath parse tree type
*/
/*! Map from axis-type int to string
@ -183,7 +183,7 @@ xpath_tree_int2str(int nodetype)
return (char*)clicon_int2str(xpath_tree_map, nodetype);
}
/*! Print XPATH parse tree
/*! Print XPath parse tree
*
* @note uses "" instead of '' in printing literals, rule [29] in https://www.w3.org/TR/xpath-10
*/
@ -217,8 +217,9 @@ xpath_tree_print0(cbuf *cb,
}
/*! Print a xpath_tree to CLIgen buf
*
* @param[out] cb CLIgen buffer
* @param[in] xs XPATH tree
* @param[in] xs XPath tree
*/
int
xpath_tree_print_cb(cbuf *cb,
@ -229,8 +230,11 @@ xpath_tree_print_cb(cbuf *cb,
}
/*! Print a xpath_tree
*
* @param[in] f UNIX output stream
* @param[in] xs XPATH tree
* @param[in] xs XPath tree
* @retval 0 OK
* @retval -1 Error
* @see xpath_tree2str
*/
int
@ -253,7 +257,8 @@ xpath_tree_print(FILE *f,
}
/*! Create an xpath string from an xpath tree, ie "unparsing"
* @param[in] xs XPATH tree
*
* @param[in] xs XPath tree
* @param[out] xpath XPath string as CLIgen buf
* @retval 0 OK
* @retval -1 Error
@ -389,9 +394,9 @@ xpath_tree_append(xpath_tree *xt,
* @param[in] xt2 XPath parse 2
* @param[in,out] vec XPath tree vector
* @param[in,out] len Length of XML XPath vector
* @retval -1 Error
* @retval 0 Not equal
* @retval 1 Equal
* @retval 0 Not equal
* @retval -1 Error
*/
int
xpath_tree_eq(xpath_tree *xt1, /* pattern */
@ -411,7 +416,7 @@ xpath_tree_eq(xpath_tree *xt1, /* pattern */
(xt2->xs_type == XP_PRIME_NR || xt2->xs_type == XP_PRIME_STR))
#endif
){
clicon_debug(CLIXON_DBG_DETAIL, "%s type %s vs %s\n", __FUNCTION__,
clixon_debug(CLIXON_DBG_DETAIL, "%s type %s vs %s\n", __FUNCTION__,
xpath_tree_int2str(xt1->xs_type),
xpath_tree_int2str(xt2->xs_type));
goto neq;
@ -423,19 +428,19 @@ xpath_tree_eq(xpath_tree *xt1, /* pattern */
goto eq;
}
if (xt1->xs_int != xt2->xs_int){
clicon_debug(CLIXON_DBG_DETAIL, "%s int\n", __FUNCTION__);
clixon_debug(CLIXON_DBG_DETAIL, "%s int\n", __FUNCTION__);
goto neq;
}
if (xt1->xs_double != xt2->xs_double){
clicon_debug(CLIXON_DBG_DETAIL, "%s double\n", __FUNCTION__);
clixon_debug(CLIXON_DBG_DETAIL, "%s double\n", __FUNCTION__);
goto neq;
}
if (clicon_strcmp(xt1->xs_s0, xt2->xs_s0)){
clicon_debug(CLIXON_DBG_DETAIL, "%s s0\n", __FUNCTION__);
clixon_debug(CLIXON_DBG_DETAIL, "%s s0\n", __FUNCTION__);
goto neq;
}
if (clicon_strcmp(xt1->xs_s1, xt2->xs_s1)){
clicon_debug(CLIXON_DBG_DETAIL, "%s s1\n", __FUNCTION__);
clixon_debug(CLIXON_DBG_DETAIL, "%s s1\n", __FUNCTION__);
goto neq;
}
xc1 = xt1->xs_c0;
@ -444,7 +449,7 @@ xpath_tree_eq(xpath_tree *xt1, /* pattern */
;
else{
if (xc1 == NULL || xc2 == NULL){
clicon_debug(CLIXON_DBG_DETAIL, "%s NULL\n", __FUNCTION__);
clixon_debug(CLIXON_DBG_DETAIL, "%s NULL\n", __FUNCTION__);
goto neq;
}
if ((ret = xpath_tree_eq(xc1, xc2, vec, len)) < 0)
@ -458,7 +463,7 @@ xpath_tree_eq(xpath_tree *xt1, /* pattern */
;
else{
if (xc1 == NULL || xc2 == NULL){
clicon_debug(CLIXON_DBG_DETAIL, "%s NULL\n", __FUNCTION__);
clixon_debug(CLIXON_DBG_DETAIL, "%s NULL\n", __FUNCTION__);
goto neq;
}
if ((ret = xpath_tree_eq(xc1, xc2, vec, len)) < 0)
@ -476,6 +481,7 @@ xpath_tree_eq(xpath_tree *xt1, /* pattern */
}
/*! Traverse through an xpath-tree using indexes
*
* @param[in] xt Start-tree
* @param[in] i List of indexes terminated by -1: 0 means c0, 1 means c1
* @retval xc End-tree
@ -506,7 +512,8 @@ xpath_tree_traverse(xpath_tree *xt,
}
/*! Free a xpath_tree
* @param[in] xs XPATH tree
*
* @param[in] xs XPath tree
* @see xpath_parse creates a xpath_tree
*/
int
@ -527,8 +534,9 @@ xpath_tree_free(xpath_tree *xs)
}
/*! Given xpath, parse it, and return structured xpath tree
* @param[in] xpath String with XPATH 1.0 syntax
* @param[out] xptree XPath-tree, parsed, structured XPATH, free:xpath_tree_free
*
* @param[in] xpath String with XPath 1.0 syntax
* @param[out] xptree XPath-tree, parsed, structured XPath, free:xpath_tree_free
* @retval 0 OK
* @retval -1 Error
* @code
@ -549,7 +557,7 @@ xpath_parse(const char *xpath,
clixon_xpath_yacc xpy = {0,};
cbuf *cb = NULL;
clicon_debug(CLIXON_DBG_DETAIL, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DETAIL, "%s", __FUNCTION__);
if (xpath == NULL){
clicon_err(OE_XML, EINVAL, "XPath is NULL");
goto done;
@ -562,19 +570,19 @@ xpath_parse(const char *xpath,
if (xpath_parse_init(&xpy) < 0)
goto done;
if (clixon_xpath_parseparse(&xpy) != 0) { /* yacc returns 1 on error */
clicon_log(LOG_NOTICE, "XPATH error: on line %d", xpy.xpy_linenum);
clicon_log(LOG_NOTICE, "XPath error: on line %d", xpy.xpy_linenum);
if (clicon_errno == 0)
clicon_err(OE_XML, 0, "XPATH parser error with no error code (should not happen)");
clicon_err(OE_XML, 0, "XPath parser error with no error code (should not happen)");
xpath_scan_exit(&xpy);
goto done;
}
if (clicon_debug_get() > 2){
if (clixon_debug_get() > 2){
if ((cb = cbuf_new()) == NULL){
clicon_err(OE_XML, errno, "cbuf_new");
goto done;
}
xpath_tree_print_cb(cb, xpy.xpy_top);
clicon_debug(CLIXON_DBG_DETAIL, "xpath parse tree:\n%s", cbuf_get(cb));
clixon_debug(CLIXON_DBG_DETAIL, "xpath parse tree:\n%s", cbuf_get(cb));
}
xpath_parse_exit(&xpy);
xpath_scan_exit(&xpy);
@ -592,13 +600,14 @@ xpath_parse(const char *xpath,
}
/*! Given XML tree and xpath, parse xpath, eval it and return xpath context,
*
* This is a raw form of xpath where you can do type conversion of the return
* value, etc, not just a nodeset.
* @param[in] xcur XML-tree where to search
* @param[in] nsc External XML namespace context, or NULL
* @param[in] xpath String with XPATH 1.0 syntax
* @param[in] xpath String with XPath 1.0 syntax
* @param[in] localonly Skip prefix and namespace tests (non-standard)
* @param[out] xrp Return XPATH context
* @param[out] xrp Return XPath context
* @retval 0 OK
* @retval -1 Error
* @code
@ -620,7 +629,7 @@ xpath_vec_ctx(cxobj *xcur,
xpath_tree *xptree = NULL;
xp_ctx xc = {0,};
clicon_debug(CLIXON_DBG_DETAIL, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DETAIL, "%s", __FUNCTION__);
if (xpath_parse(xpath, &xptree) < 0)
goto done;
xc.xc_type = XT_NODESET;
@ -645,7 +654,7 @@ xpath_vec_ctx(cxobj *xcur,
*
* @param[in] xcur XML tree where to search
* @param[in] nsc External XML namespace context, or NULL
* @param[in] xpformat Format string for XPATH syntax
* @param[in] xpformat Format string for XPath syntax
* @retval xml-tree XML tree of first match
* @retval NULL Error or not found
*
@ -706,7 +715,7 @@ xpath_first(cxobj *xcur,
*
* Reason for skipping prefix/namespace check may be with incomplete tree, for example.
* @param[in] xcur XML tree where to search
* @param[in] xpformat Format string for XPATH syntax
* @param[in] xpformat Format string for XPath syntax
* @retval xml-tree XML tree of first match
* @retval NULL Error or not found
*
@ -765,7 +774,7 @@ xpath_first_localonly(cxobj *xcur,
* If result is not nodeset, return empty nodeset
* @param[in] xcur xml-tree where to search
* @param[in] nsc External XML namespace context, or NULL
* @param[in] xpformat Format string for XPATH syntax
* @param[in] xpformat Format string for XPath syntax
* @param[out] vec vector of xml-trees. Vector must be free():d after use
* @param[out] veclen returns length of vector in return value
* @retval 0 OK
@ -832,8 +841,9 @@ xpath_vec(cxobj *xcur,
}
/* XPath that returns a vector of matches (only nodes marked with flags)
*
* @param[in] xcur xml-tree where to search
* @param[in] xpformat Format string for XPATH syntax
* @param[in] xpformat Format string for XPath syntax
* @param[in] nsc External XML namespace context, or NULL
* @param[in] flags Set of flags that return nodes must match (0 if all)
* @param[out] vec vector of xml-trees. Vector must be free():d after use
@ -911,10 +921,11 @@ xpath_vec_flag(cxobj *xcur,
}
/*! Given XML tree and xpath, returns boolean
*
* Returns true if the nodeset is non-empty
* @param[in] xcur xml-tree where to search
* @param[in] nsc External XML namespace context, or NULL
* @param[in] xpformat Format string for XPATH syntax
* @param[in] xpformat Format string for XPath syntax
* @retval 1 True
* @retval 0 False
* @retval -1 Error
@ -1111,7 +1122,7 @@ xpath2canonical(const char *xpath0,
cbuf *xcb = NULL;
int ret;
clicon_debug(CLIXON_DBG_DETAIL, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DETAIL, "%s", __FUNCTION__);
/* Parse input xpath into an xpath-tree */
if (xpath_parse(xpath0, &xpt) < 0)
goto done;
@ -1160,8 +1171,10 @@ xpath2canonical(const char *xpath0,
*
* @param[in] xcur xml-tree where to search
* @param[in] nsc External XML namespace context, or NULL
* @param[in] xpath XPATH syntax
* @param[in] xpath XPath syntax
* @param[oit] count Nr of elements of xpath
* @retval 0 OK
* @retval -1 Error
* @note This function is made for making optimizations in certain circumstances, such as a list
*/
int
@ -1465,7 +1478,7 @@ xpath2xml_traverse(xpath_tree *xs,
}
retval = 1;
done:
clicon_debug(CLIXON_DBG_DETAIL, "%s retval:%d", __FUNCTION__, retval);
clixon_debug(CLIXON_DBG_DETAIL, "%s retval:%d", __FUNCTION__, retval);
return retval;
fail:
retval = 0;
@ -1502,7 +1515,7 @@ xpath2xml(char *xpath,
cbuf *cberr = NULL;
xpath_tree *xpt = NULL;
clicon_debug(CLIXON_DBG_DETAIL, "%s xpath:%s", __FUNCTION__, xpath);
clixon_debug(CLIXON_DBG_DETAIL, "%s xpath:%s", __FUNCTION__, xpath);
if ((cberr = cbuf_new()) == NULL){
clicon_err(OE_UNIX, errno, "cbuf_new");
goto done;

View file

@ -33,8 +33,8 @@
***** END LICENSE BLOCK *****
* Clixon XML XPATH 1.0 according to https://www.w3.org/TR/xpath-10
* This file defines XPATH contexts used in traversing the XPATH parse tree.
* Clixon XML XPath 1.0 according to https://www.w3.org/TR/xpath-10
* This file defines XPath contexts used in traversing the XPath parse tree.
*/
#include <stdio.h>
#include <stdlib.h>
@ -70,7 +70,7 @@ const map_str2int ctxmap[] = {
{"nodeset", XT_NODESET},
{"bool", XT_BOOL},
{"number", XT_NUMBER},
{"string", XT_STRING},
{"string", XT_STRING},
{NULL, -1}
};
@ -91,7 +91,7 @@ xp_ctx *
ctx_dup(xp_ctx *xc0)
{
xp_ctx *xc = NULL;
if ((xc = malloc(sizeof(*xc))) == NULL){
clicon_err(OE_UNIX, errno, "malloc");
goto done;
@ -114,9 +114,10 @@ ctx_dup(xp_ctx *xc0)
return xc;
}
/*! Print XPATH context to CLIgen buf
/*! Print XPath context to CLIgen buf
*
* @param[in] cb CLIgen buf to print to
* @param[in] xc XPATH evaluation context
* @param[in] xc XPath evaluation context
* @param[in] ind Indentation margin
* @param[in] str Prefix string in printout
*/
@ -155,10 +156,13 @@ ctx_print_cb(cbuf *cb,
return 0;
}
/*! Print XPATH context
/*! Print XPath context
*
* @param[in] f File to print to
* @param[in] xc XPATH evaluation context
* @param[in] xc XPath evaluation context
* @param[in] str Prefix string in printout
* @retval 0 OK
* @retval -1 Error
*/
int
ctx_print(FILE *f,
@ -181,10 +185,11 @@ ctx_print(FILE *f,
return retval;
}
/*! Convert xpath context to boolean according to boolean() function in XPATH spec
* @param[in] xc XPATH context
* @retval 0 False
/*! Convert xpath context to boolean according to boolean() function in XPath spec
*
* @param[in] xc XPath context
* @retval 1 True
* @retval 0 False
* a number is true if and only if it is neither positive or negative zero nor NaN
* a node-set is true if and only if it is non-empty
* a string is true if and only if its length is non-zero
@ -212,8 +217,9 @@ ctx2boolean(xp_ctx *xc)
return b;
}
/*! Convert xpath context to string according to string() function in XPATH spec
* @param[in] xc XPATH context
/*! Convert xpath context to string according to string() function in XPath spec
*
* @param[in] xc XPath context
* @param[out] str0 Malloced result string
* @retval 0 OK
* @retval -1 Error
@ -227,7 +233,7 @@ ctx2string(xp_ctx *xc,
char *str = NULL;
int len;
char *b;
switch (xc->xc_type){
case XT_NODESET:
if (xc->xc_size && (b = xml_body(xc->xc_nodeset[0]))){
@ -240,7 +246,7 @@ ctx2string(xp_ctx *xc,
if ((str = strdup("")) == NULL){
clicon_err(OE_XML, errno, "strdup");
goto done;
}
}
break;
case XT_BOOL:
if ((str = strdup(xc->xc_bool == 0?"false":"true")) == NULL){
@ -270,8 +276,9 @@ ctx2string(xp_ctx *xc,
return retval;
}
/*! Convert xpath context to number according to number() function in XPATH spec
* @param[in] xc XPATH context
/*! Convert xpath context to number according to number() function in XPath spec
*
* @param[in] xc XPath context
* @param[out] n0 Floating point or NAN
* @retval 0 OK
* @retval -1 Error
@ -283,7 +290,7 @@ ctx2number(xp_ctx *xc,
int retval = -1;
char *str = NULL;
double n = NAN;
switch (xc->xc_type){
case XT_NODESET:
if (ctx2string(xc, &str) < 0)
@ -310,7 +317,7 @@ ctx2number(xp_ctx *xc,
return retval;
}
/*! Replace a nodeset of a XPATH context with a new nodeset
/*! Replace a nodeset of a XPath context with a new nodeset
*/
int
ctx_nodeset_replace(xp_ctx *xc,

View file

@ -32,7 +32,7 @@
***** END LICENSE BLOCK *****
* Clixon XML XPATH 1.0 according to https://www.w3.org/TR/xpath-10
* Clixon XML XPath 1.0 according to https://www.w3.org/TR/xpath-10
*
* Some notes on namespace extensions in Netconf/Yang
* RFC6241 8.9.1
@ -90,7 +90,7 @@
#include "clixon_xpath_function.h"
#include "clixon_xpath_eval.h"
/* Mapping between XPATH operator string <--> int */
/* Mapping between XPath operator string <--> int */
const map_str2int xpopmap[] = {
{"and", XO_AND},
{"or", XO_OR},
@ -105,14 +105,15 @@ const map_str2int xpopmap[] = {
{"<=", XO_LE},
{"<", XO_LT},
{">", XO_GT},
{"|", XO_UNION},
{"|", XO_UNION},
{NULL, -1}
};
/*! Eval an XPATH nodetest
* @retval -1 Error XXX: retval -1 not properly handled
* @retval 0 No match
/*! Eval an XPath nodetest
*
* @retval 1 Match
* @retval 0 No match
* @retval -1 Error XXX: retval -1 not properly handled
*/
static int
nodetest_eval_node(cxobj *x,
@ -140,7 +141,7 @@ nodetest_eval_node(cxobj *x,
retval = 0; /* no match */
goto done;
}
/* Here names are equal
/* Here names are equal
* Now look for namespaces
* 1) prefix1 and prefix2 point to same namespace <<-- try this first
* 2) prefix1 is equal to prefix2 <<-- then try this
@ -156,7 +157,7 @@ nodetest_eval_node(cxobj *x,
* This can happen in eg augments and ../foo, where foo is
* augmented from another namespace
*/
retval = 1;
retval = 1;
}
else
retval = (nsxml == nsxpath); /* True only if both are NULL */
@ -181,7 +182,8 @@ nodetest_eval_node(cxobj *x,
return retval;
}
/*! Eval an XPATH nodetest but skip prefix and namespace tests
/*! Eval an XPath nodetest but skip prefix and namespace tests
*
* This is NOT according to standard
*/
static int
@ -210,13 +212,14 @@ nodetest_eval_node_localonly(cxobj *x,
}
/*! Make a nodetest
*
* @param[in] x XML node
* @param[in] xs XPATH stack of type XP_NODE or XP_NODE_FN
* @param[in] xs XPath stack of type XP_NODE or XP_NODE_FN
* @param[in] nsc XML Namespace context
* @param[in] localonly Skip prefix and namespace tests (non-standard)
* @retval -1 Error
* @retval 0 No match
* @retval 1 Match
* @retval 0 No match
* @retval -1 Error
* - node() is true for any node of any type whatsoever.
* - text() is true for any text node.
*/
@ -248,18 +251,21 @@ nodetest_eval(cxobj *x,
return retval;
}
/*!
/*! test node recursive
*
* @param[in] xn
* @param[in] nodetest XPATH stack
* @param[in] nodetest XPath stack
* @param[in] node_type
* @param[in] flags
* @param[in] nsc XML Namespace context
* @param[in] localonly Skip prefix and namespace tests (non-standard)
* @param[out] vec0
* @param[out] vec0len
* @retval 0 OK
* @retval -1 Error
*/
int
nodetest_recursive(cxobj *xn,
nodetest_recursive(cxobj *xn,
xpath_tree *nodetest,
int node_type,
uint16_t flags,
@ -269,14 +275,14 @@ nodetest_recursive(cxobj *xn,
int *vec0len)
{
int retval = -1;
cxobj *xsub;
cxobj *xsub;
cxobj **vec = *vec0;
int veclen = *vec0len;
xsub = NULL;
while ((xsub = xml_child_each(xn, xsub, node_type)) != NULL) {
if (nodetest_eval(xsub, nodetest, nsc, localonly) == 1){
clicon_debug(CLIXON_DBG_DETAIL, "%s %x %x", __FUNCTION__, flags, xml_flag(xsub, flags));
clixon_debug(CLIXON_DBG_DETAIL, "%s %x %x", __FUNCTION__, flags, xml_flag(xsub, flags));
if (flags==0x0 || xml_flag(xsub, flags))
if (cxvec_append(xsub, &vec, &veclen) < 0)
goto done;
@ -294,11 +300,13 @@ nodetest_recursive(cxobj *xn,
/*! Evaluate xpath step rule of an XML tree
*
* @param[in] xc0 Incoming context
* @param[in] xs XPATH node tree
* @param[in] nsc XML Namespace context
* @param[in] xc0 Incoming context
* @param[in] xs XPath node tree
* @param[in] nsc XML Namespace context
* @param[in] localonly Skip prefix and namespace tests (non-standard)
* @param[out] xrp Resulting context
* @param[out] xrp Resulting context
* @retval 0 OK
* @retval -1 Error
*
* - A node test that is a QName is true if and only if the type of the node (see [5 Data Model])
* is the principal node type and has an expanded-name equal to the expanded-name specified by the QName.
@ -323,7 +331,7 @@ xp_eval_step(xp_ctx *xc0,
xpath_tree *nodetest = xs->xs_c0;
xp_ctx *xc = NULL;
int ret;
/* Create new xc */
if ((xc = ctx_dup(xc0)) == NULL)
goto done;
@ -344,9 +352,9 @@ xp_eval_step(xp_ctx *xc0,
xc->xc_descendant = 0;
}
else{
for (i=0; i<xc->xc_size; i++){
for (i=0; i<xc->xc_size; i++){
xv = xc->xc_nodeset[i];
x = NULL;
x = NULL;
if ((ret = xpath_optimize_check(xs, xv, &vec, &veclen)) < 0)
goto done;
if (ret == 0){/* regular code, no optimization made */
@ -358,7 +366,7 @@ xp_eval_step(xp_ctx *xc0,
goto done;
}
}
}
}
}
}
ctx_nodeset_replace(xc, vec, veclen);
@ -447,11 +455,13 @@ xp_eval_step(xp_ctx *xc0,
/*! Evaluate xpath predicates rule
*
* pred -> pred expr
* @param[in] xc Incoming context
* @param[in] xs XPATH node tree
* @param[in] nsc XML Namespace context
* @param[in] xc Incoming context
* @param[in] xs XPath node tree
* @param[in] nsc XML Namespace context
* @param[in] localonly Skip prefix and namespace tests (non-standard)
* @param[out] xrp Resulting context
* @param[out] xrp Resulting context
* @retval 0 OK
* @retval -1 Error
*
* A predicate filters a node-set with respect to an axis to produce a new
* node-set. For each node in the node-set to be filtered, the PredicateExpr is
@ -482,10 +492,10 @@ xp_eval_predicate(xp_ctx *xc,
int i;
cxobj *x;
xp_ctx *xcc = NULL;
if (xs->xs_c0 != NULL){ /* eval previous predicates */
if (xp_eval(xc, xs->xs_c0, nsc, localonly, &xr0) < 0)
goto done;
if (xp_eval(xc, xs->xs_c0, nsc, localonly, &xr0) < 0)
goto done;
}
else{ /* empty */
if ((xr0 = ctx_dup(xc)) == NULL)
@ -529,14 +539,14 @@ xp_eval_predicate(xp_ctx *xc,
if the number is equal to the context position */
if ((int)xrc->xc_number == i)
if (cxvec_append(x, &xr1->xc_nodeset, &xr1->xc_size) < 0)
goto done;
goto done;
}
else {
/* if PredicateExpr evaluates to true for that node, the node is
/* if PredicateExpr evaluates to true for that node, the node is
included in the new node-set */
if (ctx2boolean(xrc))
if (cxvec_append(x, &xr1->xc_nodeset, &xr1->xc_size) < 0)
goto done;
goto done;
}
if (xrc)
ctx_free(xrc);
@ -565,7 +575,8 @@ xp_eval_predicate(xp_ctx *xc,
return retval;
}
/*! Given two XPATH contexts, eval logical operations: or,and
/*! Given two XPath contexts, eval logical operations: or,and
*
* The logical operators convert their operands to booleans
* @param[in] xc1 Context of operand1
* @param[in] xc2 Context of operand2
@ -584,7 +595,7 @@ xp_logop(xp_ctx *xc1,
xp_ctx *xr = NULL;
int b1;
int b2;
if ((xr = malloc(sizeof(*xr))) == NULL){
clicon_err(OE_UNIX, errno, "malloc");
goto done;
@ -614,7 +625,8 @@ xp_logop(xp_ctx *xc1,
return retval;
}
/*! Given two XPATH contexts, eval numeric operations: +-*,div,mod
/*! Given two XPath contexts, eval numeric operations: +-*,div,mod
*
* The numeric operators convert their operands to numbers as if by
* calling the number function.
* @param[in] xc1 Context of operand1
@ -634,7 +646,7 @@ xp_numop(xp_ctx *xc1,
xp_ctx *xr = NULL;
double n1;
double n2;
if ((xr = malloc(sizeof(*xr))) == NULL){
clicon_err(OE_UNIX, errno, "malloc");
goto done;
@ -677,6 +689,7 @@ xp_numop(xp_ctx *xc1,
}
/*! Get xml body value as cligen variable
*
* @param[in] x XML node (body and leaf/leaf-list)
* @param[out] cvp Pointer to cligen variable containing value of x body
* @retval 0 OK, cvp contains cv or NULL
@ -700,7 +713,7 @@ xml_cv_cache(cxobj *x,
int options = 0;
uint8_t fraction = 0;
char *body;
if ((body = xml_body(x)) == NULL)
body="";
if ((cv = xml_cv(x)) != NULL)
@ -723,7 +736,6 @@ xml_cv_cache(cxobj *x,
}
if (cvtype == CGV_DEC64)
cv_dec64_n_set(cv, fraction);
if ((ret = cv_parse1(body, cv, &reason)) < 0){
clicon_err(OE_YANG, errno, "cv_parse1");
goto done;
@ -746,7 +758,8 @@ xml_cv_cache(cxobj *x,
return retval;
}
/*! Given two XPATH contexts, eval relational operations: <>=
/*! Given two XPath contexts, eval relational operations: <>=
*
* A RelationalExpr is evaluated by comparing the objects that result from
* evaluating the two operands.
* This is covered:
@ -755,7 +768,7 @@ xml_cv_cache(cxobj *x,
* (c) One is nodeset and other is INT or STRING. Result type is nodeset
* (d) All others (eg two nodesets, BOOL+STRING) are not supported.
* Op is = EQ
* From XPATH 1.0 standard, the evaluation has three variants:
* From XPath 1.0 standard, the evaluation has three variants:
* (1) comparisons that involve node-sets are defined in terms of comparisons that
* do not involve node-sets; this is defined uniformly for =, !=, <=, <, >= and >.
* (2) comparisons that do not involve node-sets are defined for = and !=.
@ -788,7 +801,7 @@ xp_relop(xp_ctx *xc1,
char *xb;
cg_var *cv1, *cv2;
int ret;
if (xc1 == NULL || xc2 == NULL){
clicon_err(OE_UNIX, EINVAL, "xc1 or xc2 NULL");
goto done;
@ -1056,7 +1069,8 @@ xp_relop(xp_ctx *xc1,
return retval;
}
/*! Given two XPATH contexts, eval union operation
/*! Given two XPath contexts, eval union operation
*
* Both operands must be nodesets, otherwise empty nodeset is returned
* @param[in] xc1 Context of operand1
* @param[in] xc2 Context of operand2
@ -1074,7 +1088,7 @@ xp_union(xp_ctx *xc1,
int retval = -1;
xp_ctx *xr = NULL;
int i;
if (op != XO_UNION){
clicon_err(OE_UNIX, errno, "%s:Invalid operator %s in this context",
__FUNCTION__, clicon_int2str(xpopmap,op));
@ -1101,12 +1115,12 @@ xp_union(xp_ctx *xc1,
return retval;
}
/*! Evaluate an XPATH on an XML tree
/*! Evaluate an XPath on an XML tree
*
* The initial sequence of steps selects a set of nodes relative to a context node.
* Each node in that set is used as a context node for the following step.
* @param[in] xc Incoming context
* @param[in] xs XPATH node tree
* @param[in] xs XPath node tree
* @param[in] nsc XML Namespace context
* @param[in] localonly Skip prefix and namespace tests (non-standard)
* @param[out] xrp Resulting context
@ -1126,7 +1140,7 @@ xp_eval(xp_ctx *xc,
xp_ctx *xr1 = NULL;
xp_ctx *xr2 = NULL;
int use_xr0 = 0; /* In 2nd child use transitively result of 1st child */
// ctx_print(stderr, xc, xpath_tree_int2str(xs->xs_type));
/* Pre-actions before check first child c0
*/
@ -1231,7 +1245,7 @@ xp_eval(xp_ctx *xc,
goto ok;
break;
default:
clicon_err(OE_XML, EFAULT, "XPATH function not implemented: %s", xs->xs_s0);
clicon_err(OE_XML, EFAULT, "XPath function not implemented: %s", xs->xs_s0);
goto done;
break;
}
@ -1243,7 +1257,7 @@ xp_eval(xp_ctx *xc,
/* Eval first child c0
*/
if (xs->xs_c0){
if (xp_eval(xc, xs->xs_c0, nsc, localonly, &xr0) < 0)
if (xp_eval(xc, xs->xs_c0, nsc, localonly, &xr0) < 0)
goto done;
}
/* Actions between first and second child
@ -1327,7 +1341,7 @@ xp_eval(xp_ctx *xc,
* Note, some operators like locationpath, need transitive context (use_xr0)
*/
if (xs->xs_c1){
if (xp_eval(use_xr0?xr0:xc, xs->xs_c1, nsc, localonly, &xr1) < 0)
if (xp_eval(use_xr0?xr0:xc, xs->xs_c1, nsc, localonly, &xr1) < 0)
goto done;
/* Actions after second child
*/

View file

@ -32,7 +32,7 @@
***** END LICENSE BLOCK *****
* Clixon XML XPATH 1.0 according to https://www.w3.org/TR/xpath-10
* Clixon XML XPath 1.0 according to https://www.w3.org/TR/xpath-10
*/
#ifndef _CLIXON_XPATH_EVAL_H
#define _CLIXON_XPATH_EVAL_H

View file

@ -32,7 +32,7 @@
***** END LICENSE BLOCK *****
* Clixon XML XPATH 1.0 according to https://www.w3.org/TR/xpath-10
* Clixon XML XPath 1.0 according to https://www.w3.org/TR/xpath-10
* and rfc 7950
*
*/
@ -74,12 +74,13 @@
#include "clixon_xpath_function.h"
/*! xpath function translation table
*
* @see enum clixon_xpath_function
*/
static const map_str2int xpath_fnname_map[] = { /* alphabetic order */
{"bit-is-set", XPATHFN_BIT_IS_SET},
{"boolean", XPATHFN_BOOLEAN},
{"eiling", XPATHFN_CEILING},
{"eiling", XPATHFN_CEILING},
{"comment", XPATHFN_COMMENT},
{"concat", XPATHFN_CONCAT},
{"contains", XPATHFN_CONTAINS},
@ -144,7 +145,7 @@ xp_function_current(xp_ctx *xc0,
cxobj **vec = NULL;
int veclen = 0;
xp_ctx *xc = NULL;
if ((xc = ctx_dup(xc0)) == NULL)
goto done;
if (cxvec_append(xc->xc_initial, &vec, &veclen) < 0)
@ -177,7 +178,7 @@ xp_function_deref(xp_ctx *xc0,
yang_stmt *yt;
yang_stmt *ypath;
char *path;
/* Create new xc */
if ((xc = ctx_dup(xc0)) == NULL)
goto done;
@ -210,6 +211,7 @@ xp_function_deref(xp_ctx *xc0,
}
/*! Helper function for derived-from(-and-self) - eval one node
*
* @param[in] nsc XML Namespace context
* @param[in] self If set, implements derived_from_or_self
* @retval 1 OK and match
@ -279,7 +281,7 @@ derived_from_one(char *baseidentity,
else {
/* Allocate cbuf */
if ((cb = cbuf_new()) == NULL){
clicon_err(OE_UNIX, errno, "cbuf_new");
clicon_err(OE_UNIX, errno, "cbuf_new");
goto done;
}
cprintf(cb, "%s:%s", yang_argument_get(ymod), id);
@ -303,8 +305,9 @@ derived_from_one(char *baseidentity,
}
/*! Eval xpath function derived-from(-and-self)
*
* @param[in] xc Incoming context
* @param[in] xs XPATH node tree
* @param[in] xs XPath node tree
* @param[in] nsc XML Namespace context
* @param[in] localonly Skip prefix and namespace tests (non-standard)
* @param[in] self If set, implements derived_from_or_self
@ -332,19 +335,19 @@ xp_function_derived_from(xp_ctx *xc,
char *identity = NULL;
int i;
int ret = 0;
if (xs == NULL || xs->xs_c0 == NULL || xs->xs_c1 == NULL){
clicon_err(OE_XML, EINVAL, "derived-from expects but did not get two arguments");
goto done;
}
/* contains two arguments in xs: boolean derived-from(node-set, string) */
/* This evolves to a set of (identityref) nodes */
if (xp_eval(xc, xs->xs_c0, nsc, localonly, &xr0) < 0)
if (xp_eval(xc, xs->xs_c0, nsc, localonly, &xr0) < 0)
goto done;
if (xr0->xc_type != XT_NODESET)
goto done;
/* This evolves to a string identity */
if (xp_eval(xc, xs->xs_c1, nsc, localonly, &xr1) < 0)
if (xp_eval(xc, xs->xs_c1, nsc, localonly, &xr1) < 0)
goto done;
if (ctx2string(xr1, &identity) < 0)
goto done;
@ -385,7 +388,7 @@ xp_function_derived_from(xp_ctx *xc,
* Signature: boolean bit-is-set(node-set nodes, string bit-name)
* @param[in] xc Incoming context
* @param[in] xs XPATH node tree
* @param[in] xs XPath node tree
* @param[in] nsc XML Namespace context
* @param[in] localonly Skip prefix and namespace tests (non-standard)
* @param[out] xrp Resulting context
@ -410,16 +413,16 @@ xp_function_bit_is_set(xp_ctx *xc,
char *s1 = NULL;
cxobj *x;
char *body;
if (xs == NULL || xs->xs_c0 == NULL || xs->xs_c1 == NULL){
clicon_err(OE_XML, EINVAL, "contains expects but did not get two arguments");
goto done;
}
/* First node-set argument */
if (xp_eval(xc, xs->xs_c0, nsc, localonly, &xr0) < 0)
if (xp_eval(xc, xs->xs_c0, nsc, localonly, &xr0) < 0)
goto done;
/* Second string argument */
if (xp_eval(xc, xs->xs_c1, nsc, localonly, &xr1) < 0)
if (xp_eval(xc, xs->xs_c1, nsc, localonly, &xr1) < 0)
goto done;
if (ctx2string(xr1, &s1) < 0)
goto done;
@ -454,7 +457,7 @@ xp_function_bit_is_set(xp_ctx *xc,
*
* Signature: number position(node-set)
* @param[in] xc Incoming context
* @param[in] xs XPATH node tree
* @param[in] xs XPath node tree
* @param[in] nsc XML Namespace context
* @param[in] localonly Skip prefix and namespace tests (non-standard)
* @param[out] xrp Resulting context
@ -470,7 +473,7 @@ xp_function_position(xp_ctx *xc,
{
int retval = -1;
xp_ctx *xr = NULL;
if ((xr = malloc(sizeof(*xr))) == NULL){
clicon_err(OE_UNIX, errno, "malloc");
goto done;
@ -499,12 +502,12 @@ xp_function_count(xp_ctx *xc,
int retval = -1;
xp_ctx *xr = NULL;
xp_ctx *xr0 = NULL;
if (xs == NULL || xs->xs_c0 == NULL){
clicon_err(OE_XML, EINVAL, "count expects but did not get one argument");
goto done;
}
if (xp_eval(xc, xs->xs_c0, nsc, localonly, &xr0) < 0)
if (xp_eval(xc, xs->xs_c0, nsc, localonly, &xr0) < 0)
goto done;
if ((xr = malloc(sizeof(*xr))) == NULL){
clicon_err(OE_UNIX, errno, "malloc");
@ -541,12 +544,12 @@ xp_function_name(xp_ctx *xc,
char *s0 = NULL;
int i;
cxobj *x;
if (xs == NULL || xs->xs_c0 == NULL){
clicon_err(OE_XML, EINVAL, "not expects but did not get one argument");
goto done;
}
if (xp_eval(xc, xs->xs_c0, nsc, localonly, &xr0) < 0)
if (xp_eval(xc, xs->xs_c0, nsc, localonly, &xr0) < 0)
goto done;
if ((xr = malloc(sizeof(*xr))) == NULL){
clicon_err(OE_UNIX, errno, "malloc");
@ -574,8 +577,9 @@ xp_function_name(xp_ctx *xc,
}
/*! Eval xpath function contains
*
* @param[in] xc Incoming context
* @param[in] xs XPATH node tree
* @param[in] xs XPath node tree
* @param[in] nsc XML Namespace context
* @param[in] localonly Skip prefix and namespace tests (non-standard)
* @param[out] xrp Resulting context
@ -602,11 +606,11 @@ xp_function_contains(xp_ctx *xc,
goto done;
}
/* contains two arguments in xs: boolean contains(string, string) */
if (xp_eval(xc, xs->xs_c0, nsc, localonly, &xr0) < 0)
if (xp_eval(xc, xs->xs_c0, nsc, localonly, &xr0) < 0)
goto done;
if (ctx2string(xr0, &s0) < 0)
goto done;
if (xp_eval(xc, xs->xs_c1, nsc, localonly, &xr1) < 0)
if (xp_eval(xc, xs->xs_c1, nsc, localonly, &xr1) < 0)
goto done;
if (ctx2string(xr1, &s1) < 0)
goto done;
@ -653,12 +657,12 @@ xp_function_boolean(xp_ctx *xc,
xp_ctx *xr = NULL;
xp_ctx *xr0 = NULL;
int bool;
if (xs == NULL || xs->xs_c0 == NULL){
clicon_err(OE_XML, EINVAL, "not expects but did not get one argument");
goto done;
}
if (xp_eval(xc, xs->xs_c0, nsc, localonly, &xr0) < 0)
if (xp_eval(xc, xs->xs_c0, nsc, localonly, &xr0) < 0)
goto done;
bool = ctx2boolean(xr0);
if ((xr = malloc(sizeof(*xr))) == NULL){
@ -706,7 +710,7 @@ xp_function_true(xp_ctx *xc,
{
int retval = -1;
xp_ctx *xr = NULL;
if ((xr = malloc(sizeof(*xr))) == NULL){
clicon_err(OE_UNIX, errno, "malloc");
goto done;
@ -733,7 +737,7 @@ xp_function_false(xp_ctx *xc,
{
int retval = -1;
xp_ctx *xr = NULL;
if ((xr = malloc(sizeof(*xr))) == NULL){
clicon_err(OE_UNIX, errno, "malloc");
goto done;

View file

@ -32,7 +32,7 @@
***** END LICENSE BLOCK *****
* Clixon XML XPATH 1.0 according to https://www.w3.org/TR/xpath-10 (Base XML)
* Clixon XML XPath 1.0 according to https://www.w3.org/TR/xpath-10 (Base XML)
* and rfc 7950 (YANG-specific)
*/
#ifndef _CLIXON_XPATH_FUNCTION_H

View file

@ -32,7 +32,7 @@
***** END LICENSE BLOCK *****
* Clixon XML XPATH 1.0 according to https://www.w3.org/TR/xpath-10
* Clixon XML XPath 1.0 according to https://www.w3.org/TR/xpath-10
* See XPATH_LIST_OPTIMIZE
*/
@ -89,6 +89,7 @@ xpath_list_optimize_stats(int *hits)
}
/*! Enable xpath optimize
*
* Cant replace this with option since there is no handle in xpath functions,...
*/
int
@ -111,6 +112,7 @@ xpath_optimize_exit(void)
#ifdef XPATH_LIST_OPTIMIZE
/*! Initialize xpath module
*
* XXX move to clixon_xpath.c
* @see loop_preds
*/
@ -120,10 +122,10 @@ xpath_optimize_init(xpath_tree **xm,
{
int retval = -1;
xpath_tree *xs;
if (_xm == NULL){
/* Initialize xpath-tree */
if (xpath_parse("_x[_y='_z']", &_xmtop) < 0)
if (xpath_parse("_x[_y='_z']", &_xmtop) < 0)
goto done;
/* Go down two steps */
if ((_xm = xpath_tree_traverse(_xmtop, 0, 0, -1)) == NULL)
@ -161,9 +163,9 @@ xpath_optimize_init(xpath_tree **xm,
* @param[in] xt XPath tree of type PRED
* @param[in] xepat Pattern matching XPath tree of type EXPR
* @param[out] cvk Vector of <keyname>:<keyval> pairs
* @retval -1 Error
* @retval 0 No match
* @retval 1 Match
* @retval 0 No match
* @retval -1 Error
* @see xpath_optimize_init
*/
static int
@ -177,7 +179,7 @@ loop_preds(xpath_tree *xt,
xpath_tree **vec = NULL;
size_t veclen = 0;
cg_var *cvi;
if (xt->xs_type == XP_PRED && xt->xs_c0){
if ((ret = loop_preds(xt->xs_c0, xepat, cvk)) < 0)
goto done;
@ -192,7 +194,7 @@ loop_preds(xpath_tree *xt,
if (veclen != 2)
goto ok;
if ((cvi = cvec_add(cvk, CGV_STRING)) == NULL){
clicon_err(OE_XML, errno, "cvec_add");
clicon_err(OE_XML, errno, "cvec_add");
goto done;
}
cv_name_set(cvi, vec[0]->xs_s1);
@ -219,9 +221,9 @@ loop_preds(xpath_tree *xt,
* @param[out] xlen Len of xvec
* @param[out] key
* @param[out] keyval
* @retval -1 Error
* @retval 0 No match - use non-optimized lookup
* @retval 1 Match
* @retval 0 No match - use non-optimized lookup
* @retval -1 Error
* XPath:
* y[k=3] # corresponds to: <name>[<keyname>=<keyval>]
*/
@ -245,7 +247,7 @@ xpath_list_optimize_fn(xpath_tree *xt,
cg_var *cvi;
int i;
yang_stmt *ypp;
/* revert to non-optimized if no yang */
if ((yp = xml_spec(xv)) == NULL)
goto ok;
@ -277,13 +279,13 @@ xpath_list_optimize_fn(xpath_tree *xt,
#ifdef NOTYET /* leaf-list is not detected by xpath optimize detection */
if ((yc = yang_find(yp, Y_LEAF_LIST, name)) == NULL) /* XXX */
#endif
goto ok;
goto ok;
/* Validate keys */
if ((cvv = yang_cvec_get(yc)) == NULL)
goto ok;
xtp = vec[1];
if ((cvk = cvec_new(0)) == NULL){
clicon_err(OE_YANG, errno, "cvec_new");
clicon_err(OE_YANG, errno, "cvec_new");
goto done;
}
if ((ret = loop_preds(xtp, xem, cvk)) < 0)
@ -316,23 +318,23 @@ xpath_list_optimize_fn(xpath_tree *xt,
}
#endif /* XPATH_LIST_OPTIMIZE */
/*! Identify XPATH special cases and if match, use binary search.
/*! Identify XPath special cases and if match, use binary search.
*
* @retval -1 Error
* @retval 0 Dont optimize: not special case, do normal processing
* @retval 1 Optimization made, special case, use x (found if != NULL)
* @retval 0 Dont optimize: not special case, do normal processing
* @retval -1 Error
* XXX Contains glue code between cxobj ** and clixon_xvec code
*/
int
xpath_optimize_check(xpath_tree *xs,
cxobj *xv,
cxobj ***xvec0,
cxobj ***xvec0,
int *xlen0)
{
#ifdef XPATH_LIST_OPTIMIZE
int ret;
clixon_xvec *xvec = NULL;
if (!_optimize_enable)
return 0; /* use regular code */
if ((xvec = clixon_xvec_new()) == NULL)

View file

@ -32,7 +32,7 @@
***** END LICENSE BLOCK *****
* Clixon XML XPATH 1.0 according to https://www.w3.org/TR/xpath-10
* Clixon XML XPath 1.0 according to https://www.w3.org/TR/xpath-10
*/
#ifndef _CLIXON_XPATH_PARSE_H_
#define _CLIXON_XPATH_PARSE_H_
@ -40,7 +40,7 @@
/*
* Types
*/
struct clixon_xpath_yacc{
struct clixon_xpath_yacc{
const char *xpy_name; /* Name of syntax (for error string) */
int xpy_linenum; /* Number of \n in parsed buffer */
const char *xpy_parse_string; /* original (copy of) parse string */

View file

@ -91,7 +91,7 @@ There are some special lexical rules in https://www.w3.org/TR/xpath-10
#define _XPY ((clixon_xpath_yacc *)_yy)
#undef clixon_xpath_parsewrap
int
int
clixon_xpath_parsewrap(void)
{
return 1;
@ -120,7 +120,7 @@ ncname {namestart}{namechar}*
%s ALITERAL
%%
<TOKEN0>[ \t]
<TOKEN0>[ \t]
<TOKEN0>\n { _XPY->xpy_linenum++; }
<TOKEN0>\r { }
<TOKEN0><<EOF>> { return X_EOF; }
@ -147,11 +147,11 @@ ncname {namestart}{namechar}*
<TOKEN0>{ncname} { /* See lexical rules 2 and 3 in the file header */
clixon_xpath_parselval.string = strdup(yytext);
return NCNAME;
}
return NCNAME;
}
<TOKEN0>. { fprintf(stderr,"LEXICAL ERROR\n"); return -1; }
<TOKEN2>[ \t]
<TOKEN2>[ \t]
<TOKEN2>\n { _XPY->xpy_linenum++; }
<TOKEN2>\r { }
<TOKEN2><<EOF>> { return X_EOF; }
@ -175,15 +175,15 @@ ncname {namestart}{namechar}*
<TOKEN2>\' { BEGIN(TOKEN0); _XPY->xpy_lex_string_state=TOKEN2; BEGIN(ALITERAL); return APOST; }
<TOKEN2>\-?({integer}|{real}) { BEGIN(TOKEN0); clixon_xpath_parselval.string = strdup(yytext); return NUMBER; }
<TOKEN2>comment\( { BEGIN(TOKEN0); clixon_xpath_parselval.string = strdup(yytext); striplast(clixon_xpath_parselval.string); return NODETYPE; }
<TOKEN2>text\( { BEGIN(TOKEN0); clixon_xpath_parselval.string = strdup(yytext); striplast(clixon_xpath_parselval.string); return NODETYPE; }
<TOKEN2>processing-instructions\( { BEGIN(TOKEN0); clixon_xpath_parselval.string = strdup(yytext); striplast(clixon_xpath_parselval.string); return NODETYPE; }
<TOKEN2>node\( { BEGIN(TOKEN0); clixon_xpath_parselval.string = strdup(yytext); striplast(clixon_xpath_parselval.string); return NODETYPE; }
<TOKEN2>comment\( { BEGIN(TOKEN0); clixon_xpath_parselval.string = strdup(yytext); striplast(clixon_xpath_parselval.string); return NODETYPE; }
<TOKEN2>text\( { BEGIN(TOKEN0); clixon_xpath_parselval.string = strdup(yytext); striplast(clixon_xpath_parselval.string); return NODETYPE; }
<TOKEN2>processing-instructions\( { BEGIN(TOKEN0); clixon_xpath_parselval.string = strdup(yytext); striplast(clixon_xpath_parselval.string); return NODETYPE; }
<TOKEN2>node\( { BEGIN(TOKEN0); clixon_xpath_parselval.string = strdup(yytext); striplast(clixon_xpath_parselval.string); return NODETYPE; }
<TOKEN2>{ncname} { /* See lexical rules 2 and 3 in the file header */
BEGIN(TOKEN0);
BEGIN(TOKEN0);
clixon_xpath_parselval.string = strdup(yytext);
return NCNAME;
}
return NCNAME;
}
<TOKEN2>. { fprintf(stderr,"LEXICAL ERROR\n"); return -1; }
<QLITERAL>\" { BEGIN(_XPY->xpy_lex_string_state); return QUOTE; }
@ -205,7 +205,7 @@ xpath_scan_init(clixon_xpath_yacc *xpy)
xpy->xpy_lexbuf = yy_scan_string (xpy->xpy_parse_string);
#if 1 /* XXX: just to use unput to avoid warning */
if (0)
yyunput(0, "");
yyunput(0, "");
#endif
return 0;

View file

@ -32,7 +32,7 @@
***** END LICENSE BLOCK *****
* XPATH Parser
* XPath Parser
* From https://www.w3.org/TR/xpath-10/
* The primary syntactic construct in XPath is the expression.
* An expression matches the production Expr
@ -101,7 +101,7 @@
#define _YYERROR(msg) {clicon_err(OE_XML, 0, "YYERROR %s '%s' %d", (msg), clixon_xpath_parsetext, _XPY->xpy_linenum); YYERROR;}
/* add _yy to error parameters */
#define YY_(msgid) msgid
#define YY_(msgid) msgid
#include "clixon_config.h"
@ -134,12 +134,12 @@
/* Best debugging is to enable PARSE_DEBUG below and add -d to the LEX compile statement in the Makefile
* And then run the testcase with -D 1
* Disable it to stop any calls to clicon_debug. Having it on by default would mean very large debug outputs.
* Disable it to stop any calls to clixon_debug. Having it on by default would mean very large debug outputs.
*/
#if 0
#define _PARSE_DEBUG(s) clicon_debug(1,(s))
#define _PARSE_DEBUG1(s, s1) clicon_debug(1,(s), (s1))
#define _PARSE_DEBUG2(s, s1, s2) clicon_debug(1,(s), (s1), (s2))
#define _PARSE_DEBUG(s) clixon_debug(1,(s))
#define _PARSE_DEBUG1(s, s1) clixon_debug(1,(s), (s1))
#define _PARSE_DEBUG2(s, s1, s2) clixon_debug(1,(s), (s1), (s2))
#else
#define _PARSE_DEBUG(s)
#define _PARSE_DEBUG1(s, s1)
@ -148,27 +148,27 @@
extern int clixon_xpath_parseget_lineno (void); /*XXX obsolete ? */
/*
/*
also called from yacc generated code *
*/
void
void
clixon_xpath_parseerror(void *_xpy,
char *s)
{
char *s)
{
errno = 0;
clicon_err(OE_XML, 0, "%s on line %d: %s at or before: '%s'", /* Note lineno here is xpath, not yang */
_XPY->xpy_name,
_XPY->xpy_linenum ,
s,
clixon_xpath_parsetext);
return;
_XPY->xpy_linenum,
s,
clixon_xpath_parsetext);
return;
}
int
xpath_parse_init(clixon_xpath_yacc *xpy)
{
// clicon_debug_init(3, NULL);
// clixon_debug_init(3, NULL);
return 0;
}
@ -177,11 +177,11 @@ xpath_parse_exit(clixon_xpath_yacc *xpy)
{
return 0;
}
/*! Generic creator function for an xpath tree object
*
* @param[in] type XPATH tree node type
* @param[in] i0 step-> axis_type
* @param[in] type XPath tree node type
* @param[in] i0 step-> axis_type
* @param[in] numstr original string xs_double: numeric value
* @param[in] s0 String 0 set if XP_PRIME_STR, XP_PRIME_FN, XP_NODE[_FN] PATHEXPRE prefix
* @param[in] s1 String 1 set if XP_NODE NAME (or "*")
@ -198,7 +198,7 @@ xp_new(enum xp_type type,
xpath_tree *c1)
{
xpath_tree *xs = NULL;
if ((xs = malloc(sizeof(xpath_tree))) == NULL){
clicon_err(OE_XML, errno, "malloc");
goto done;
@ -239,7 +239,7 @@ xp_primary_function(clixon_xpath_yacc *xpy,
enum clixon_xpath_function fn;
cbuf *cb = NULL;
int ret;
if ((ret = xp_fnname_str2int(name)) < 0){
if ((cb = cbuf_new()) == NULL){
clicon_err(OE_XML, errno, "cbuf_new");
@ -253,7 +253,7 @@ xp_primary_function(clixon_xpath_yacc *xpy,
switch (fn){
case XPATHFN_RE_MATCH: /* Group of NOT IMPLEMENTED xpath functions */
case XPATHFN_ENUM_VALUE:
case XPATHFN_LAST:
case XPATHFN_LAST:
case XPATHFN_ID:
case XPATHFN_LOCAL_NAME:
case XPATHFN_NAMESPACE_URI:
@ -276,7 +276,7 @@ xp_primary_function(clixon_xpath_yacc *xpy,
clicon_err(OE_XML, errno, "cbuf_new");
goto done;
}
cprintf(cb, "XPATH function \"%s\" is not implemented", name);
cprintf(cb, "XPath function \"%s\" is not implemented", name);
clixon_xpath_parseerror(xpy, cbuf_get(cb));
goto done;
break;
@ -294,14 +294,14 @@ xp_primary_function(clixon_xpath_yacc *xpy,
case XPATHFN_TRUE:
case XPATHFN_FALSE:
break;
default:
default:
if ((cb = cbuf_new()) == NULL){
clicon_err(OE_XML, errno, "cbuf_new");
goto done;
}
cprintf(cb, "Unknown xpath function \"%s\"", name);
clixon_xpath_parseerror(xpy, cbuf_get(cb));
goto done;
goto done;
break;
}
if (cb)
@ -349,21 +349,21 @@ xp_nodetest_function(clixon_xpath_yacc *xpy,
clicon_err(OE_XML, errno, "cbuf_new");
goto done;
}
cprintf(cb, "XPATH function \"%s\" is not implemented", name);
cprintf(cb, "XPath function \"%s\" is not implemented", name);
clixon_xpath_parseerror(xpy, cbuf_get(cb));
goto done;
break;
case XPATHFN_TEXT: /* Group of implemented node functions */
case XPATHFN_NODE:
case XPATHFN_NODE:
break;
default:
default:
if ((cb = cbuf_new()) == NULL){
clicon_err(OE_XML, errno, "cbuf_new");
goto done;
}
cprintf(cb, "Unknown xpath nodetest function \"%s\"", name);
clixon_xpath_parseerror(xpy, cbuf_get(cb));
goto done;
goto done;
break;
}
if (cb)
@ -404,63 +404,63 @@ xp_axisname_function(clixon_xpath_yacc *xpy,
return fn;
}
%}
%}
%%
/*
*/
start : expr X_EOF { _XPY->xpy_top=$1;_PARSE_DEBUG("start->expr"); YYACCEPT; }
| locationpath X_EOF { _XPY->xpy_top=$1;_PARSE_DEBUG("start->locationpath"); YYACCEPT; }
start : expr X_EOF { _XPY->xpy_top=$1;_PARSE_DEBUG("start->expr"); YYACCEPT; }
| locationpath X_EOF { _XPY->xpy_top=$1;_PARSE_DEBUG("start->locationpath"); YYACCEPT; }
;
expr : expr LOGOP andexpr { $$=xp_new(XP_EXP,$2,NULL,NULL,NULL,$1, $3);_XPY->xpy_top=$$; _PARSE_DEBUG("expr->expr or andexpr"); }
| andexpr { $$=xp_new(XP_EXP,A_NAN,NULL,NULL,NULL,$1, NULL);_XPY->xpy_top=$$;_PARSE_DEBUG("expr-> andexpr"); }
expr : expr LOGOP andexpr { $$=xp_new(XP_EXP,$2,NULL,NULL,NULL,$1, $3);_XPY->xpy_top=$$; _PARSE_DEBUG("expr->expr or andexpr"); }
| andexpr { $$=xp_new(XP_EXP,A_NAN,NULL,NULL,NULL,$1, NULL);_XPY->xpy_top=$$;_PARSE_DEBUG("expr-> andexpr"); }
;
andexpr : andexpr LOGOP relexpr { $$=xp_new(XP_AND,$2,NULL,NULL,NULL,$1, $3);_XPY->xpy_top=$$;_PARSE_DEBUG("andexpr-> andexpr and relexpr"); }
| relexpr { $$=xp_new(XP_AND,A_NAN,NULL,NULL,NULL,$1, NULL);_XPY->xpy_top=$$;_PARSE_DEBUG("andexpr-> relexpr"); }
andexpr : andexpr LOGOP relexpr { $$=xp_new(XP_AND,$2,NULL,NULL,NULL,$1, $3);_XPY->xpy_top=$$;_PARSE_DEBUG("andexpr-> andexpr and relexpr"); }
| relexpr { $$=xp_new(XP_AND,A_NAN,NULL,NULL,NULL,$1, NULL);_XPY->xpy_top=$$;_PARSE_DEBUG("andexpr-> relexpr"); }
;
relexpr : relexpr RELOP addexpr { $$=xp_new(XP_RELEX,$2,NULL,NULL,NULL,$1, $3);_XPY->xpy_top=$$;_PARSE_DEBUG("relexpr-> relexpr relop addexpr"); }
| addexpr { $$=xp_new(XP_RELEX,A_NAN,NULL,NULL,NULL,$1, NULL);_XPY->xpy_top=$$;_PARSE_DEBUG("relexpr-> addexpr"); }
relexpr : relexpr RELOP addexpr { $$=xp_new(XP_RELEX,$2,NULL,NULL,NULL,$1, $3);_XPY->xpy_top=$$;_PARSE_DEBUG("relexpr-> relexpr relop addexpr"); }
| addexpr { $$=xp_new(XP_RELEX,A_NAN,NULL,NULL,NULL,$1, NULL);_XPY->xpy_top=$$;_PARSE_DEBUG("relexpr-> addexpr"); }
;
addexpr : addexpr ADDOP unionexpr { $$=xp_new(XP_ADD,$2,NULL,NULL,NULL,$1, $3);_XPY->xpy_top=$$;_PARSE_DEBUG("addexpr-> addexpr ADDOP unionexpr"); }
| unionexpr { $$=xp_new(XP_ADD,A_NAN,NULL,NULL,NULL,$1, NULL);_XPY->xpy_top=$$;_PARSE_DEBUG("addexpr-> unionexpr"); }
addexpr : addexpr ADDOP unionexpr { $$=xp_new(XP_ADD,$2,NULL,NULL,NULL,$1, $3);_XPY->xpy_top=$$;_PARSE_DEBUG("addexpr-> addexpr ADDOP unionexpr"); }
| unionexpr { $$=xp_new(XP_ADD,A_NAN,NULL,NULL,NULL,$1, NULL);_XPY->xpy_top=$$;_PARSE_DEBUG("addexpr-> unionexpr"); }
;
/* node-set */
unionexpr : unionexpr '|' pathexpr { $$=xp_new(XP_UNION,XO_UNION,NULL,NULL,NULL,$1, $3);_XPY->xpy_top=$$;_PARSE_DEBUG("unionexpr-> unionexpr | pathexpr"); }
| pathexpr { $$=xp_new(XP_UNION,A_NAN,NULL,NULL,NULL,$1, NULL);_XPY->xpy_top=$$;_PARSE_DEBUG("unionexpr-> pathexpr"); }
unionexpr : unionexpr '|' pathexpr { $$=xp_new(XP_UNION,XO_UNION,NULL,NULL,NULL,$1, $3);_XPY->xpy_top=$$;_PARSE_DEBUG("unionexpr-> unionexpr | pathexpr"); }
| pathexpr { $$=xp_new(XP_UNION,A_NAN,NULL,NULL,NULL,$1, NULL);_XPY->xpy_top=$$;_PARSE_DEBUG("unionexpr-> pathexpr"); }
;
pathexpr : locationpath { $$=xp_new(XP_PATHEXPR,A_NAN,NULL,NULL,NULL,$1, NULL);_XPY->xpy_top=$$;_PARSE_DEBUG("pathexpr-> locationpath"); }
pathexpr : locationpath { $$=xp_new(XP_PATHEXPR,A_NAN,NULL,NULL,NULL,$1, NULL);_XPY->xpy_top=$$;_PARSE_DEBUG("pathexpr-> locationpath"); }
| filterexpr { $$=xp_new(XP_PATHEXPR,A_NAN,NULL,NULL,NULL,$1, NULL);_XPY->xpy_top=$$;_PARSE_DEBUG("pathexpr-> filterexpr"); }
| filterexpr '/' rellocpath { $$=xp_new(XP_PATHEXPR,A_NAN,NULL,strdup("/"),NULL,$1, $3);_XPY->xpy_top=$$;_PARSE_DEBUG("pathexpr-> filterexpr / rellocpath"); }
| filterexpr DOUBLESLASH rellocpath { $$=xp_new(XP_PATHEXPR,A_NAN,NULL,strdup("//"),NULL,$1, $3);_XPY->xpy_top=$$;_PARSE_DEBUG("pathexpr-> filterexpr // rellocpath"); }
| filterexpr DOUBLESLASH rellocpath { $$=xp_new(XP_PATHEXPR,A_NAN,NULL,strdup("//"),NULL,$1, $3);_XPY->xpy_top=$$;_PARSE_DEBUG("pathexpr-> filterexpr // rellocpath"); }
;
/* */
filterexpr : primaryexpr { $$=xp_new(XP_FILTEREXPR,A_NAN,NULL,NULL,NULL,$1, NULL);_PARSE_DEBUG("filterexpr-> primaryexpr"); }
filterexpr : primaryexpr { $$=xp_new(XP_FILTEREXPR,A_NAN,NULL,NULL,NULL,$1, NULL);_PARSE_DEBUG("filterexpr-> primaryexpr"); }
/* Filterexpr predicate */
;
/* location path returns a node-set */
locationpath : rellocpath { $$=xp_new(XP_LOCPATH,A_NAN,NULL,NULL,NULL,$1, NULL); _PARSE_DEBUG("locationpath-> rellocpath"); }
| abslocpath { $$=xp_new(XP_LOCPATH,A_NAN,NULL,NULL,NULL,$1, NULL); _PARSE_DEBUG("locationpath-> abslocpath"); }
locationpath : rellocpath { $$=xp_new(XP_LOCPATH,A_NAN,NULL,NULL,NULL,$1, NULL); _PARSE_DEBUG("locationpath-> rellocpath"); }
| abslocpath { $$=xp_new(XP_LOCPATH,A_NAN,NULL,NULL,NULL,$1, NULL); _PARSE_DEBUG("locationpath-> abslocpath"); }
;
abslocpath : '/' { $$=xp_new(XP_ABSPATH,A_ROOT,NULL,NULL,NULL,NULL, NULL);_PARSE_DEBUG("abslocpath-> /"); }
| '/' rellocpath { $$=xp_new(XP_ABSPATH,A_ROOT,NULL,NULL,NULL,$2, NULL);_PARSE_DEBUG("abslocpath->/ rellocpath");}
/* // is short for /descendant-or-self::node()/ */
| DOUBLESLASH rellocpath {$$=xp_new(XP_ABSPATH,A_DESCENDANT_OR_SELF,NULL,NULL,NULL,$2, NULL); _PARSE_DEBUG("abslocpath-> // rellocpath"); }
| DOUBLESLASH rellocpath {$$=xp_new(XP_ABSPATH,A_DESCENDANT_OR_SELF,NULL,NULL,NULL,$2, NULL); _PARSE_DEBUG("abslocpath-> // rellocpath"); }
;
rellocpath : step { $$=xp_new(XP_RELLOCPATH,A_NAN,NULL,NULL,NULL,$1, NULL); _PARSE_DEBUG("rellocpath-> step"); }
| rellocpath '/' step { $$=xp_new(XP_RELLOCPATH,A_NAN,NULL,NULL,NULL,$1, $3);_PARSE_DEBUG("rellocpath-> rellocpath / step"); }
| rellocpath DOUBLESLASH step { $$=xp_new(XP_RELLOCPATH,A_DESCENDANT_OR_SELF,NULL,NULL,NULL,$1, $3); _PARSE_DEBUG("rellocpath-> rellocpath // step"); }
rellocpath : step { $$=xp_new(XP_RELLOCPATH,A_NAN,NULL,NULL,NULL,$1, NULL); _PARSE_DEBUG("rellocpath-> step"); }
| rellocpath '/' step { $$=xp_new(XP_RELLOCPATH,A_NAN,NULL,NULL,NULL,$1, $3);_PARSE_DEBUG("rellocpath-> rellocpath / step"); }
| rellocpath DOUBLESLASH step { $$=xp_new(XP_RELLOCPATH,A_DESCENDANT_OR_SELF,NULL,NULL,NULL,$1, $3); _PARSE_DEBUG("rellocpath-> rellocpath // step"); }
;
step : nodetest predicates
@ -472,8 +472,8 @@ step : nodetest predicates
| abbreviatedstep { $$ = $1; }
;
abbreviatedstep : '.' predicates { $$=xp_new(XP_STEP,A_SELF, NULL,NULL, NULL, NULL, $2); _PARSE_DEBUG("step-> ."); }
| DOUBLEDOT predicates { $$=xp_new(XP_STEP, A_PARENT, NULL,NULL, NULL, NULL, $2); _PARSE_DEBUG("step-> .."); }
abbreviatedstep : '.' predicates { $$=xp_new(XP_STEP,A_SELF, NULL,NULL, NULL, NULL, $2); _PARSE_DEBUG("step-> ."); }
| DOUBLEDOT predicates { $$=xp_new(XP_STEP, A_PARENT, NULL,NULL, NULL, NULL, $2); _PARSE_DEBUG("step-> .."); }
;
/* [5] AxisSpecifier::= AxisName '::'
@ -481,7 +481,7 @@ abbreviatedstep : '.' predicates { $$=xp_new(XP_STEP,A_SELF, NULL,NULL, NULL
*/
axisspec : NCNAME DOUBLECOLON
{ if (($$=xp_axisname_function(_XPY, $1)) < 0) YYERROR;
free($1);
free($1);
_PARSE_DEBUG2("axisspec-> AXISNAME(%s -> %d) ::", $1, $$);
}
| abbreviatedaxisspec
@ -509,22 +509,22 @@ nametest : ADDOP
_PARSE_DEBUG("nametest-> *"); }
| NCNAME
{ $$=xp_new(XP_NODE,A_NAN,NULL, NULL, $1, NULL, NULL);
_PARSE_DEBUG1("nametest-> name[%s]",$1); }
_PARSE_DEBUG1("nametest-> name[%s]",$1); }
| NCNAME ':' NCNAME
{ $$=xp_new(XP_NODE,A_NAN,NULL, $1, $3, NULL, NULL);
_PARSE_DEBUG2("nametest-> name[%s] : name[%s]", $1, $3); }
_PARSE_DEBUG2("nametest-> name[%s] : name[%s]", $1, $3); }
| NCNAME ':' '*'
{ $$=xp_new(XP_NODE,A_NAN,NULL, $1, NULL, NULL, NULL);
_PARSE_DEBUG1("nametest-> name[%s] : *", $1); }
_PARSE_DEBUG1("nametest-> name[%s] : *", $1); }
;
/* evaluates to boolean */
predicates : predicates '[' expr ']' { $$=xp_new(XP_PRED,A_NAN,NULL, NULL, NULL, $1, $3); _PARSE_DEBUG("predicates-> [ expr ]"); }
| { $$=xp_new(XP_PRED,A_NAN,NULL, NULL, NULL, NULL, NULL); _PARSE_DEBUG("predicates->"); }
predicates : predicates '[' expr ']' { $$=xp_new(XP_PRED,A_NAN,NULL, NULL, NULL, $1, $3); _PARSE_DEBUG("predicates-> [ expr ]"); }
| { $$=xp_new(XP_PRED,A_NAN,NULL, NULL, NULL, NULL, NULL); _PARSE_DEBUG("predicates->"); }
;
primaryexpr : '(' expr ')' { $$=xp_new(XP_PRI0,A_NAN,NULL, NULL, NULL, $2, NULL); _PARSE_DEBUG("primaryexpr-> ( expr )"); }
primaryexpr : '(' expr ')' { $$=xp_new(XP_PRI0,A_NAN,NULL, NULL, NULL, $2, NULL); _PARSE_DEBUG("primaryexpr-> ( expr )"); }
| literal { $$ = $1; }
| NUMBER { $$=xp_new(XP_PRIME_NR,A_NAN, $1, NULL, NULL, NULL, NULL);_PARSE_DEBUG1("primaryexpr-> NUMBER(%s)", $1); /*XXX*/}
| NUMBER { $$=xp_new(XP_PRIME_NR,A_NAN, $1, NULL, NULL, NULL, NULL);_PARSE_DEBUG1("primaryexpr-> NUMBER(%s)", $1); /*XXX*/}
| functioncall { $$ = $1; }
;
@ -539,13 +539,13 @@ literal : QUOTE string QUOTE
_PARSE_DEBUG("literal-> \" string \""); }
| QUOTE QUOTE
{ $$=xp_new(XP_PRIME_STR,A_NAN,NULL, strdup(""), NULL, NULL, NULL);
_PARSE_DEBUG("primaryexpr-> \" \""); }
_PARSE_DEBUG("primaryexpr-> \" \""); }
| APOST string APOST
{ $$=xp_new(XP_PRIME_STR,A_NAN,NULL, $2, NULL, NULL, NULL);
_PARSE_DEBUG("primaryexpr-> ' string '"); }
| APOST APOST
{ $$=xp_new(XP_PRIME_STR,A_NAN,NULL, strdup(""), NULL, NULL, NULL);
_PARSE_DEBUG("primaryexpr-> ' '"); }
_PARSE_DEBUG("primaryexpr-> ' '"); }
;
functioncall : NCNAME '(' ')'
@ -554,17 +554,17 @@ functioncall : NCNAME '(' ')'
_PARSE_DEBUG("primaryexpr-> functionname ()"); }
| NCNAME '(' args ')'
{ if (($$ = xp_primary_function(_XPY, $1, $3)) == NULL) YYERROR;
_PARSE_DEBUG("primaryexpr-> functionname (arguments)"); }
_PARSE_DEBUG("primaryexpr-> functionname (arguments)"); }
;
string : string CHARS {
string : string CHARS {
int len = strlen($1);
$$ = realloc($1, len+strlen($2) + 1);
sprintf($$+len, "%s", $2);
$$ = realloc($1, len+strlen($2) + 1);
sprintf($$+len, "%s", $2);
free($2);
_PARSE_DEBUG("string-> string CHAR");
}
| CHARS { _PARSE_DEBUG("string-> "); }
| CHARS { _PARSE_DEBUG("string-> "); }
;

View file

@ -32,9 +32,9 @@
***** END LICENSE BLOCK *****
* Clixon XML XPATH 1.0 according to https://www.w3.org/TR/xpath-10
* Clixon XML XPath 1.0 according to https://www.w3.org/TR/xpath-10
* Note: for YANG which is constrained to path-arg as defined in rfc7950
* See: clixon_xpath.[ch] for full XML XPATH implementation
* See: clixon_xpath.[ch] for full XML XPath implementation
*/
#ifdef HAVE_CONFIG_H
#include "clixon_config.h" /* generated by config & autoconf */
@ -86,7 +86,7 @@ xp_yang_ctx *
xy_dup(xp_yang_ctx *xy0)
{
xp_yang_ctx *xy = NULL;
if ((xy = malloc(sizeof(*xy))) == NULL){
clicon_err(OE_UNIX, errno, "malloc");
goto done;
@ -115,7 +115,7 @@ xp_yang_op_eq(xp_yang_ctx *xy1,
{
int retval = -1;
xp_yang_ctx *xy = NULL;
if ((xy = xy_dup(xy1)) == NULL)
goto done;
if (xy1 == NULL || xy2 == NULL || xy1->xy_node == NULL || xy2->xy_node == NULL){
@ -134,7 +134,7 @@ xp_yang_op_eq(xp_yang_ctx *xy1,
/*! Evaluate leafref PATH-ARG step rule on a YANG tree
*
* @param[in] xy0 Incoming context
* @param[in] xpath_tree XPATH parse-tree
* @param[in] xpath_tree XPath parse-tree
* @param[out] xyr Resulting context
* @retval 0 OK
* @retval -1 Error
@ -157,7 +157,7 @@ xp_yang_eval_step(xp_yang_ctx *xy0,
goto done;
ys = xy->xy_node;
switch (xptree->xs_int){
case A_CHILD:
case A_CHILD:
if ((nodetest = xptree->xs_c0) == NULL){
clicon_err(OE_YANG, 0, "child step nodetest expected");
goto done;
@ -221,7 +221,7 @@ xp_yang_eval_step(xp_yang_ctx *xy0,
/*! Evaluate leafref PATH-ARG predicate rule on a YANG tree
*
* @param[in] xy Incoming context
* @param[in] xpath_tree XPATH parse-tree
* @param[in] xpath_tree XPath parse-tree
* @param[out] xyr Resulting context
* @retval 0 OK
* @retval -1 Error
@ -237,7 +237,7 @@ xp_yang_eval_predicate(xp_yang_ctx *xy,
xp_yang_ctx *xy1 = NULL;
if (xptree->xs_c0 != NULL){ /* eval previous predicates */
if (xp_yang_eval(xy, xptree->xs_c0, &xy0) < 0)
if (xp_yang_eval(xy, xptree->xs_c0, &xy0) < 0)
goto done;
}
else{ /* empty */
@ -270,7 +270,7 @@ xp_yang_eval_predicate(xp_yang_ctx *xy,
/*! Evaluate leafref PATH-ARG on a YANG tree
*
* @param[in] xy Incoming context
* @param[in] xpath_tree XPATH parse-tree
* @param[in] xpath_tree XPath parse-tree
* @param[out] xyr Resulting context
* @retval 0 OK
* @retval -1 Error
@ -358,7 +358,7 @@ xp_yang_eval(xp_yang_ctx *xy,
/* Eval first child c0
*/
if (xptree->xs_c0){
if (xp_yang_eval(xy, xptree->xs_c0, &xy0) < 0)
if (xp_yang_eval(xy, xptree->xs_c0, &xy0) < 0)
goto done;
}
/* Actions between first and second child
@ -379,7 +379,7 @@ xp_yang_eval(xp_yang_ctx *xy,
* Note, some operators like locationpath, need transitive context (use_xr0)
*/
if (xptree->xs_c1){
if (xp_yang_eval(use_xy0?xy0:xy, xptree->xs_c1, &xy1) < 0)
if (xp_yang_eval(use_xy0?xy0:xy, xptree->xs_c1, &xy1) < 0)
goto done;
/* Actions after second child
*/
@ -447,7 +447,7 @@ xp_yang_eval(xp_yang_ctx *xy,
* @param[out] yref YANG referred node
* @retval 0 OK
* @retval -1 Error
* @note this function uses XPATH parser, which is (much too) general
* @note this function uses XPath parser, which is (much too) general
* @code
* yang_stmt *ys; // source / referring node
* yang_stmt *yref = NULL; // target / referred node
@ -470,7 +470,7 @@ yang_path_arg(yang_stmt *ys,
xp_yang_ctx *xyr = NULL;
xp_yang_ctx *xy = NULL;
clicon_debug(CLIXON_DBG_DETAIL, "%s", __FUNCTION__);
clixon_debug(CLIXON_DBG_DETAIL, "%s", __FUNCTION__);
if (path_arg == NULL){
clicon_err(OE_XML, EINVAL, "path-arg is NULL");
goto done;

File diff suppressed because it is too large Load diff

Some files were not shown because too many files have changed in this diff Show more