C-style update: Unified comment, retvals in order, remove trailing spaces
Changed function name for `clicon_debug` functions
This commit is contained in:
parent
6e314dd96f
commit
62348fc9c7
204 changed files with 6047 additions and 4904 deletions
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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] */
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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)));
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -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_ */
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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{
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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]);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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");}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 = ⅇ
|
||||
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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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; }
|
||||
|
|
|
|||
|
|
@ -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 *
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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){
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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; }
|
||||
;
|
||||
|
||||
%%
|
||||
|
|
|
|||
|
|
@ -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), >mp) < 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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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; }
|
||||
|
|
|
|||
|
|
@ -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 -> "); }
|
||||
;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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-> "); }
|
||||
;
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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
Loading…
Add table
Add a link
Reference in a new issue