clixon/lib/src/clixon_options.c
Olof hagsand 6ff36a2894 * Added xml_wrap function that adds an XML node above a node as a wrapper
* also renamed `xml_insert` to `xml_wrap_all`.
* Added `clicon_argv_get()` function to get the user command-line options, ie the args in `-- <args>`. This is an alternative to using them passed to `plugin_start()`.
2019-03-27 16:04:14 +01:00

1105 lines
29 KiB
C

/*
*
***** BEGIN LICENSE BLOCK *****
Copyright (C) 2009-2019 Olof Hagsand and Benny Holmgren
This file is part of CLIXON.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Alternatively, the contents of this file may be used under the terms of
the GNU General Public License Version 3 or later (the "GPL"),
in which case the provisions of the GPL are applicable instead
of those above. If you wish to allow use of your version of this file only
under the terms of the GPL, and not to allow others to
use your version of this file under the terms of Apache License version 2, indicate
your decision by deleting the provisions above and replace them with the
notice and other provisions required by the GPL. If you do not delete
the provisions above, a recipient may use your version of this file under
the terms of any one of the Apache License version 2 or the GPL.
***** END LICENSE BLOCK *****
*
* This file contains access functions for two types of clixon vars:
* - options, ie string based variables from Clixon configuration files.
* Accessed with clicon_options(h).
* - data. Free-typed values for runtime getting and setting.
* Accessed with clicon_data(h).
* Consider splitting?
*/
#ifdef HAVE_CONFIG_H
#include "clixon_config.h" /* generated by config & autoconf */
#endif
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <stdlib.h>
#include <stdint.h>
#include <syslog.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/param.h>
#include <sys/socket.h>
/* cligen */
#include <cligen/cligen.h>
/* clicon */
#include "clixon_err.h"
#include "clixon_string.h"
#include "clixon_queue.h"
#include "clixon_hash.h"
#include "clixon_handle.h"
#include "clixon_log.h"
#include "clixon_yang.h"
#include "clixon_xml.h"
#include "clixon_xml_sort.h"
#include "clixon_options.h"
#include "clixon_plugin.h"
#include "clixon_xpath_ctx.h"
#include "clixon_xpath.h"
#include "clixon_xml_map.h"
/* Mapping between Clicon startup modes string <--> constants,
see clixon-config.yang type startup_mode */
static const map_str2int startup_mode_map[] = {
{"none", SM_NONE},
{"running", SM_RUNNING},
{"startup", SM_STARTUP},
{"init", SM_INIT},
{NULL, -1}
};
/*! Print registry on file. For debugging.
*/
void
clicon_option_dump(clicon_handle h,
int dbglevel)
{
clicon_hash_t *hash = clicon_options(h);
int i;
char **keys;
void *val;
size_t klen;
size_t vlen;
if (hash == NULL)
return;
keys = hash_keys(hash, &klen);
if (keys == NULL)
return;
for(i = 0; i < klen; i++) {
val = 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);
else
clicon_debug(dbglevel, "%s =\t 0x%p , length %zu", keys[i], val, vlen);
}
else
clicon_debug(dbglevel, "%s = NULL", keys[i]);
}
free(keys);
}
/*! Read filename and set values to global options registry. XML variant.
*
* @param[out] xconfig Pointer to xml config tree. Should be freed by caller
* @retval 0 OK
* @retval -1 Error
*/
static int
parse_configfile(clicon_handle h,
const char *filename,
yang_spec *yspec,
cxobj **xconfig)
{
struct stat st;
FILE *f = NULL;
int retval = -1;
int fd;
cxobj *xt = NULL;
cxobj *xc = NULL;
cxobj *x = NULL;
char *name;
char *body;
clicon_hash_t *copt = clicon_options(h);
cbuf *cbret = NULL;
int ret;
if (filename == NULL || !strlen(filename)){
clicon_err(OE_UNIX, 0, "Not specified");
goto done;
}
if (stat(filename, &st) < 0){
clicon_err(OE_UNIX, errno, "%s", filename);
goto done;
}
if (!S_ISREG(st.st_mode)){
clicon_err(OE_UNIX, 0, "%s is not a regular file", filename);
goto done;
}
if ((f = fopen(filename, "r")) == NULL) {
clicon_err(OE_UNIX, errno, "configure file: %s", filename);
return -1;
}
clicon_debug(2, "%s: Reading config file %s", __FUNCTION__, filename);
fd = fileno(f);
if (xml_parse_file(fd, "</clicon>", yspec, &xt) < 0)
goto done;
if (xml_child_nr(xt)==1 && xml_child_nr_type(xt, CX_BODY)==1){
clicon_err(OE_CFG, 0, "Config file %s: Expected XML but is probably old sh style", filename);
goto done;
}
/* Hard-coded config for < 3.10 and clixon-config for >= 3.10 */
if ((xc = xpath_first(xt, "clixon-config")) == NULL){
/* Backward compatible code to accept "config" as top-level symbol.
This cannot be controlled by config option due to bootstrap */
#if 0
if ((xc = xpath_first(xt, "config")) != NULL){
if (xml_name_set(xc, "clixon-config") < 0)
goto done;
if (xml_apply0(xc, CX_ELMNT, xml_spec_populate, yspec) < 0)
goto done;
if (xml_apply0(xc, CX_ELMNT, xml_sort, NULL) < 0)
goto done;
}
else
#endif
{
clicon_err(OE_CFG, 0, "Config file %s: Lacks top-level \"clixon-config\" element\nClixon config files should begin with: <clixon-config xmlns=\"http://clicon.org/config\" (See Changelog in Clixon 3.10)>", filename);
goto done;
}
}
if (xml_apply0(xc, CX_ELMNT, xml_default, yspec) < 0)
goto done;
if ((cbret = cbuf_new()) == NULL){
clicon_err(OE_XML, errno, "cbuf_new");
goto done;
}
if ((ret = xml_yang_validate_add(xc, cbret)) < 0)
goto done;
if (ret == 0){
clicon_err(OE_CFG, 0, "Config file validation: %s", cbuf_get(cbret));
goto done;
}
while ((x = xml_child_each(xc, x, CX_ELMNT)) != NULL) {
name = xml_name(x);
body = xml_body(x);
if (name==NULL || body == NULL){
clicon_log(LOG_WARNING, "%s option NULL: name:%s body:%s",
__FUNCTION__, name, body);
continue;
}
/* hard-coded exceptions for configure options that are leaf-lists (not leaf)
* They must be accessed directly by looping over clicon_conf_xml(h)
*/
if (strcmp(name,"CLICON_FEATURE")==0)
continue;
if (strcmp(name,"CLICON_YANG_DIR")==0)
continue;
/* Used as an arg to this fn */
if (strcmp(name,"CLICON_CONFIGFILE")==0)
continue;
if (hash_add(copt,
name,
body,
strlen(body)+1) == NULL)
goto done;
}
retval = 0;
*xconfig = xt;
xt = NULL;
done:
if (cbret)
cbuf_free(cbret);
if (xt)
xml_free(xt);
if (f)
fclose(f);
return retval;
}
/*! Add configuration option overriding file setting
* Add to clicon_options hash, and to clicon_conf_xml tree
* @param[in] h Clicon handle
* @param[in] name Name of configuration option (see clixon-config.yang)
* @param[in] value String value
* @retval 0 OK
* @retval -1 Error
* @see clicon_options_main For loading options from file
*/
int
clicon_option_add(clicon_handle h,
char *name,
char *value)
{
int retval = -1;
clicon_hash_t *copt = clicon_options(h);
cxobj *x;
if (strcmp(name, "CLICON_FEATURE")==0 ||
strcmp(name, "CLICON_YANG_DIR")==0){
if ((x = clicon_conf_xml(h)) == NULL)
goto done;
if (xml_parse_va(&x, NULL, "<%s>%s</%s>",
name, value, name) < 0)
goto done;
}
if (hash_add(copt,
name,
value,
strlen(value)+1) == NULL)
goto done;
retval = 0;
done:
return retval;
}
/*! Parse clixon yang file. Parse XML config file. Initialize option values
*
* 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
* @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.
*/
int
clicon_options_main(clicon_handle h,
yang_spec *yspec)
{
int retval = -1;
char *configfile;
clicon_hash_t *copt = clicon_options(h);
char *suffix;
char xml = 0; /* Configfile is xml, otherwise legacy */
cxobj *xconfig = NULL;
/*
* Set configure file if not set by command-line above
*/
if (!hash_lookup(copt, "CLICON_CONFIGFILE")){
clicon_option_str_set(h, "CLICON_CONFIGFILE", CLIXON_DEFAULT_CONFIG);
}
configfile = hash_value(copt, "CLICON_CONFIGFILE", NULL);
clicon_debug(1, "CLICON_CONFIGFILE=%s", configfile);
/* File must end with .xml */
if ((suffix = rindex(configfile, '.')) != NULL){
suffix++;
xml = strcmp(suffix, "xml") == 0;
}
if (xml == 0){
clicon_err(OE_CFG, 0, "%s: suffix %s not recognized", configfile, suffix);
goto done;
}
/* Read configfile first without yangspec, for bootstrapping, see second
* time below with proper yangspec.
* (You need to read the config-file to get the YANG_DIR to find the
* the clixon yang-spec)
* Difference from parsing with yangspec is:
* - no default values
* - no sanity checks
*/
if (parse_configfile(h, configfile, yspec, &xconfig) < 0)
goto done;
if (xml_rootchild(xconfig, 0, &xconfig) < 0)
goto done;
/* Set clixon_conf pointer to handle */
clicon_conf_xml_set(h, xconfig);
/* Parse clixon yang spec */
if (yang_spec_parse_module(h, "clixon-config", NULL, yspec) < 0)
goto done;
clicon_conf_xml_set(h, NULL);
if (xconfig){
xml_free(xconfig);
xconfig = NULL;
}
/* Read configfile second time now with check yang spec */
if (parse_configfile(h, configfile, yspec, &xconfig) < 0)
goto done;
if (xml_rootchild(xconfig, 0, &xconfig) < 0)
goto done;
if (xml_spec(xconfig) == NULL){
clicon_err(OE_CFG, 0, "Config file %s: did not find corresponding Yang specification\nHint: File does not begin with: <clixon-config xmlns=\"http://clicon.org/config\"> or clixon-config.yang not found?", configfile);
goto done;
}
/* Set clixon_conf pointer to handle */
clicon_conf_xml_set(h, xconfig);
retval = 0;
done:
return retval;
}
/*! Check if a clicon option has a value
* @param[in] h clicon_handle
* @param[in] name option name
* @retval !=0 option exists
* @retval 0 option does not exists
*/
int
clicon_option_exists(clicon_handle h,
const char *name)
{
clicon_hash_t *copt = clicon_options(h);
return (hash_lookup(copt, (char*)name) != NULL);
}
/*! Get a single string option string via handle
*
* @param[in] h clicon_handle
* @param[in] name option name
* @retval NULL If option not found, or value of option is NULL
* @retval string value of option if found
* clicon options should be strings.
* @note To differentiate the two reasons why NULL may be returned, use function
* clicon_option_exists() before the call
*/
char *
clicon_option_str(clicon_handle h,
const char *name)
{
clicon_hash_t *copt = clicon_options(h);
if (hash_lookup(copt, (char*)name) == NULL)
return NULL;
return hash_value(copt, (char*)name, NULL);
}
/*! Set a single string option via handle
* @param[in] h clicon_handle
* @param[in] name option name
* @param[in] val option value, must be null-terminated string
* @retval 0 OK
* @retval -1 Error
*/
int
clicon_option_str_set(clicon_handle h,
const char *name,
char *val)
{
clicon_hash_t *copt = clicon_options(h);
return hash_add(copt, (char*)name, val, strlen(val)+1)==NULL?-1:0;
}
/*! Get options as integer but stored as string
*
* @param[in] h clicon handle
* @param[in] name name of option
* @retval int An integer as aresult of atoi
* @retval -1 If option does not exist
* @code
* if (clicon_option_exists(h, "X")
* return clicon_option_int(h, "X");
* else
* return 0;
* @endcode
* Note that -1 can be both error and value.
* This means that it should be used together with clicon_option_exists() and
* supply a defualt value as shown in the example.
*/
int
clicon_option_int(clicon_handle h,
const char *name)
{
char *s;
if ((s = clicon_option_str(h, name)) == NULL)
return -1;
return atoi(s);
}
/*! Set option given as int.
*/
int
clicon_option_int_set(clicon_handle h,
const char *name,
int val)
{
char s[64];
if (snprintf(s, sizeof(s)-1, "%u", val) < 0)
return -1;
return clicon_option_str_set(h, name, s);
}
/*! Get options as bool but stored as string
*
* @param[in] h clicon handle
* @param[in] name name of option
* @retval 0 false, or does not exist, or does not have a boolean value
* @retval 1 true
* @code
* if (clicon_option_exists(h, "X")
* return clicon_option_bool(h, "X");
* else
* return 0; # default false?
* @endcode
* Note that 0 can be both error and false.
* This means that it should be used together with clicon_option_exists() and
* supply a default value as shown in the example.
*/
int
clicon_option_bool(clicon_handle h,
const char *name)
{
char *s;
if ((s = clicon_option_str(h, name)) == NULL)
return 0;
if (strcmp(s,"true")==0)
return 1;
return 0; /* Hopefully false, but anything else than "true" */
}
/*! Set option given as bool
*/
int
clicon_option_bool_set(clicon_handle h,
const char *name,
int val)
{
char s[64];
if (snprintf(s, sizeof(s)-1, "%u", val) < 0)
return -1;
return clicon_option_str_set(h, name, s);
}
/*! Delete option
*/
int
clicon_option_del(clicon_handle h,
const char *name)
{
clicon_hash_t *copt = clicon_options(h);
return hash_del(copt, (char*)name);
}
/*-----------------------------------------------------------------
* Specific option access functions for YANG configuration variables.
* Sometimes overridden by command-line options,
* such as -f for CLICON_CONFIGFILE
* @see yang/clixon-config@<date>.yang
* You can always use the basic access functions, such as
* clicon_option_str[_set]
* But sometimes there are type conversions, etc which makes it more
* convenient to make wrapper functions. Or not?
*-----------------------------------------------------------------*/
/*! Whether to generate CLIgen syntax from datamodel or not (0 or 1)
* Must be used with a previous clicon_option_exists().
* @see clixon-config@<date>.yang CLICON_CLI_GENMODEL
*/
int
clicon_cli_genmodel(clicon_handle h)
{
char const *opt = "CLICON_CLI_GENMODEL";
if (clicon_option_exists(h, opt))
return clicon_option_int(h, opt);
else
return 0;
}
/*! Generate code for CLI completion of existing db symbols
* @see clixon-config@<date>.yang CLICON_CLI_GENMODEL_COMPLETION
*/
int
clicon_cli_genmodel_completion(clicon_handle h)
{
char const *opt = "CLICON_CLI_GENMODEL_COMPLETION";
if (clicon_option_exists(h, opt))
return clicon_option_int(h, opt);
else
return 0;
}
/*! How to generate and show CLI syntax: VARS|ALL
* @see clixon-config@<date>.yang CLICON_CLI_GENMODEL_TYPE
*/
enum genmodel_type
clicon_cli_genmodel_type(clicon_handle h)
{
char *s;
enum genmodel_type gt = GT_ERR;
if (!clicon_option_exists(h, "CLICON_CLI_GENMODEL_TYPE")){
gt = GT_VARS;
goto done;
}
s = clicon_option_str(h, "CLICON_CLI_GENMODEL_TYPE");
if (strcmp(s, "NONE")==0)
gt = GT_NONE;
else
if (strcmp(s, "VARS")==0)
gt = GT_VARS;
else
if (strcmp(s, "ALL")==0)
gt = GT_ALL;
done:
return gt;
}
/*! Get Dont include keys in cvec in cli vars callbacks
* @see clixon-config@<date>.yang CLICON_CLI_VARONLY
*/
int
clicon_cli_varonly(clicon_handle h)
{
char const *opt = "CLICON_CLI_VARONLY";
if (clicon_option_exists(h, opt))
return clicon_option_int(h, opt);
else
return 0;
}
/*! Get family of backend socket: AF_UNIX, AF_INET or AF_INET6
* @see clixon-config@<date>.yang CLICON_SOCK_FAMILY
*/
int
clicon_sock_family(clicon_handle h)
{
char *s;
if ((s = clicon_option_str(h, "CLICON_SOCK_FAMILY")) == NULL)
return AF_UNIX;
else if (strcmp(s, "IPv4")==0)
return AF_INET;
else if (strcmp(s, "IPv6")==0)
return AF_INET6;
else
return AF_UNIX; /* default */
}
/*! Get port for backend socket in case of AF_INET or AF_INET6
* @see clixon-config@<date>.yang CLICON_SOCK_PORT
*/
int
clicon_sock_port(clicon_handle h)
{
char *s;
if ((s = clicon_option_str(h, "CLICON_SOCK_PORT")) == NULL)
return -1;
return atoi(s);
}
/*! Set if all configuration changes are committed automatically
*/
int
clicon_autocommit(clicon_handle h)
{
char const *opt = "CLICON_AUTOCOMMIT";
if (clicon_option_exists(h, opt))
return clicon_option_int(h, opt);
else
return 0;
}
/*! Which method to boot/start clicon backen
*/
int
clicon_startup_mode(clicon_handle h)
{
char *mode;
if ((mode = clicon_option_str(h, "CLICON_STARTUP_MODE")) == NULL)
return -1;
return clicon_str2int(startup_mode_map, mode);
}
/*---------------------------------------------------------------------
* Specific option access functions for non-yang options
* Typically dynamic values and more complex datatypes,
* Such as handles to plugins, API:s and parsed structures
*--------------------------------------------------------------------*/
/* eg -q option, dont print notifications on stdout */
int
clicon_quiet_mode(clicon_handle h)
{
char *s;
if ((s = clicon_option_str(h, "CLICON_QUIET")) == NULL)
return 0; /* default */
return atoi(s);
}
int
clicon_quiet_mode_set(clicon_handle h, int val)
{
return clicon_option_int_set(h, "CLICON_QUIET", val);
}
/*! Get YANG specification for application
* Must use hash functions directly since they are not strings.
*/
yang_spec *
clicon_dbspec_yang(clicon_handle h)
{
clicon_hash_t *cdat = clicon_data(h);
size_t len;
void *p;
if ((p = hash_value(cdat, "dbspec_yang", &len)) != NULL)
return *(yang_spec **)p;
return NULL;
}
/*! Set yang specification for application
* ys must be a malloced pointer
*/
int
clicon_dbspec_yang_set(clicon_handle h,
struct yang_spec *ys)
{
clicon_hash_t *cdat = clicon_data(h);
/* It is the pointer to ys that should be copied by hash,
so we send a ptr to the ptr to indicate what to copy.
*/
if (hash_add(cdat, "dbspec_yang", &ys, sizeof(ys)) == NULL)
return -1;
return 0;
}
/*! Get NACM (rfc 8341) XML parse tree if external not in std xml config
* @param[in] h Clicon handle
* @retval xn XML NACM tree, or NULL
* @note only used if config option CLICON_NACM_MODE is external
* @see clicon_nacm_ext_set
*/
cxobj *
clicon_nacm_ext(clicon_handle h)
{
clicon_hash_t *cdat = clicon_data(h);
size_t len;
void *p;
if ((p = hash_value(cdat, "nacm_xml", &len)) != NULL)
return *(cxobj **)p;
return NULL;
}
/*! Set NACM (rfc 8341) external XML parse tree, free old if any
* @param[in] h Clicon handle
* @param[in] xn XML Nacm tree
* @note only used if config option CLICON_NACM_MODE is external
* @see clicon_nacm_ext
*/
int
clicon_nacm_ext_set(clicon_handle h,
cxobj *xn)
{
clicon_hash_t *cdat = clicon_data(h);
cxobj *xo;
if ((xo = clicon_nacm_ext(h)) != NULL)
xml_free(xo);
/* It is the pointer to xn that should be copied by hash,
so we send a ptr to the ptr to indicate what to copy.
*/
if (hash_add(cdat, "nacm_xml", &xn, sizeof(xn)) == NULL)
return -1;
return 0;
}
#if 1 /* Temporary function until "Top-level Yang symbol cannot be called "config"" is fixed */
/*! Get YANG specification for clixon config
* Must use hash functions directly since they are not strings.
*/
yang_spec *
clicon_config_yang(clicon_handle h)
{
clicon_hash_t *cdat = clicon_data(h);
size_t len;
void *p;
if ((p = hash_value(cdat, "control_yang", &len)) != NULL)
return *(yang_spec **)p;
return NULL;
}
/*! Set yang specification for control
* ys must be a malloced pointer
*/
int
clicon_config_yang_set(clicon_handle h,
struct yang_spec *ys)
{
clicon_hash_t *cdat = clicon_data(h);
/* It is the pointer to ys that should be copied by hash,
so we send a ptr to the ptr to indicate what to copy.
*/
if (hash_add(cdat, "control_yang", &ys, sizeof(ys)) == NULL)
return -1;
return 0;
}
#endif
/*! 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.
*/
cxobj *
clicon_conf_xml(clicon_handle h)
{
clicon_hash_t *cdat = clicon_data(h);
size_t len;
void *p;
if ((p = hash_value(cdat, "clixon_conf", &len)) != NULL)
return *(cxobj **)p;
return NULL;
}
/*! Set YANG specification for Clixon system options and features
* ys must be a malloced pointer
*/
int
clicon_conf_xml_set(clicon_handle h,
cxobj *x)
{
clicon_hash_t *cdat = clicon_data(h);
/* It is the pointer to x that should be copied by hash,
* so we send a ptr to the ptr to indicate what to copy.
*/
if (hash_add(cdat, "clixon_conf", &x, sizeof(x)) == NULL)
return -1;
return 0;
}
/*! Get xmldb datastore plugin handle, as used by dlopen/dlsym/dlclose */
plghndl_t
clicon_xmldb_plugin_get(clicon_handle h)
{
clicon_hash_t *cdat = clicon_data(h);
size_t len;
void *p;
if ((p = hash_value(cdat, "xmldb_plugin", &len)) != NULL)
return *(plghndl_t*)p;
return NULL;
}
/*! Set xmldb datastore plugin handle, as used by dlopen/dlsym/dlclose */
int
clicon_xmldb_plugin_set(clicon_handle h,
plghndl_t handle)
{
clicon_hash_t *cdat = clicon_data(h);
if (hash_add(cdat, "xmldb_plugin", &handle, sizeof(void*)) == NULL)
return -1;
return 0;
}
/*! Get XMLDB API struct pointer
* @param[in] h Clicon handle
* @retval xa XMLDB API struct
* @note xa is really of type struct xmldb_api*
*/
void *
clicon_xmldb_api_get(clicon_handle h)
{
clicon_hash_t *cdat = clicon_data(h);
size_t len;
void *xa;
if ((xa = hash_value(cdat, "xmldb_api", &len)) != NULL)
return *(void**)xa;
return NULL;
}
/*! Set or reset XMLDB API struct pointer
* @param[in] h Clicon handle
* @param[in] xa XMLDB API struct
* @note xa is really of type struct xmldb_api*
*/
int
clicon_xmldb_api_set(clicon_handle h,
void *xa)
{
clicon_hash_t *cdat = clicon_data(h);
/* It is the pointer to xa_api that should be copied by hash,
so we send a ptr to the ptr to indicate what to copy.
*/
if (hash_add(cdat, "xmldb_api", &xa, sizeof(void*)) == NULL)
return -1;
return 0;
}
/*! Get XMLDB storage handle
* @param[in] h Clicon handle
* @retval xh XMLDB storage handle. If not connected return NULL
*/
void *
clicon_xmldb_handle_get(clicon_handle h)
{
clicon_hash_t *cdat = clicon_data(h);
size_t len;
void *xh;
if ((xh = hash_value(cdat, "xmldb_handle", &len)) != NULL)
return *(void**)xh;
return NULL;
}
/*! Set or reset XMLDB storage handle
* @param[in] h Clicon handle
* @param[in] xh XMLDB storage handle. If NULL reset it
* @note Just keep note of it, dont allocate it or so.
*/
int
clicon_xmldb_handle_set(clicon_handle h,
void *xh)
{
clicon_hash_t *cdat = clicon_data(h);
if (hash_add(cdat, "xmldb_handle", &xh, sizeof(void*)) == NULL)
return -1;
return 0;
}
/*! Get authorized user name
* @param[in] h Clicon handle
* @retval xh XMLDB storage handle. If not connected return NULL
*/
char *
clicon_username_get(clicon_handle h)
{
clicon_hash_t *cdat = clicon_data(h);
return (char*)hash_value(cdat, "username", NULL);
}
/*! Set authorized user name
* @param[in] h Clicon handle
* @param[in] xh XMLDB storage handle. If NULL reset it
* @note Just keep note of it, dont allocate it or so.
*/
int
clicon_username_set(clicon_handle h,
void *username)
{
clicon_hash_t *cdat = clicon_data(h);
if (username == NULL)
return hash_del(cdat, "username");
return hash_add(cdat, "username", username, strlen(username)+1)==NULL?-1:0;
}
/*! Get backend daemon startup status
* @param[in] h Clicon handle
* @retval status Startup status
*/
enum startup_status
clicon_startup_status_get(clicon_handle h)
{
clicon_hash_t *cdat = clicon_data(h);
void *p;
if ((p = hash_value(cdat, "startup_status", NULL)) != NULL)
return *(enum startup_status *)p;
return STARTUP_ERR;
}
/*! Set backend daemon startup status
* @param[in] h Clicon handle
* @param[in] status Startup status
* @retval 0 OK
* @retval -1 Error (when setting value)
*/
int
clicon_startup_status_set(clicon_handle h,
enum startup_status status)
{
clicon_hash_t *cdat = clicon_data(h);
if (hash_add(cdat, "startup_status", &status, sizeof(status))==NULL)
return -1;
return 0;
}
/*! Get socket fd (ie backend server socket / restconf fcgx socket)
* @param[in] h Clicon handle
* @retval -1 No open socket
* @retval s Socket
*/
int
clicon_socket_get(clicon_handle h)
{
clicon_hash_t *cdat = clicon_data(h);
void *p;
if ((p = hash_value(cdat, "socket", NULL)) == NULL)
return -1;
return *(int*)p;
}
/*! Set socket fd (ie backend server socket / restconf fcgx socket)
* @param[in] h Clicon handle
* @param[in] s Open socket (or -1 to close)
* @retval 0 OK
* @retval -1 Error
*/
int
clicon_socket_set(clicon_handle h,
int s)
{
clicon_hash_t *cdat = clicon_data(h);
if (s == -1)
return hash_del(cdat, "socket");
return hash_add(cdat, "socket", &s, sizeof(int))==NULL?-1:0;
}
/*! Get module state cache
* @param[in] h Clicon handle
* @retval xms Module state cache XML tree
*/
cxobj *
clicon_module_state_get(clicon_handle h)
{
clicon_hash_t *cdat = clicon_data(h);
void *p;
if ((p = hash_value(cdat, "module_state_cache", NULL)) != NULL)
return *(cxobj **)p;
return NULL;
}
/*! Set module state cache
* @param[in] h Clicon handle
* @param[in] xms Module state cache XML tree
* @retval 0 OK
* @retval -1 Error
*/
int
clicon_module_state_set(clicon_handle h,
cxobj *xms)
{
clicon_hash_t *cdat = clicon_data(h);
if (hash_add(cdat, "module_state_cache", &xms, sizeof(xms))==NULL)
return -1;
return 0;
}
/*! Get yang module changelog
* @param[in] h Clicon handle
* @retval xch Module revision changelog XML tree
* @see draft-wang-netmod-module-revision-management-01
*/
cxobj *
clicon_xml_changelog_get(clicon_handle h)
{
clicon_hash_t *cdat = clicon_data(h);
void *p;
if ((p = hash_value(cdat, "xml-changelog", NULL)) != NULL)
return *(cxobj **)p;
return NULL;
}
/*! Set xml module changelog
* @param[in] h Clicon 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,
cxobj *xchlog)
{
clicon_hash_t *cdat = clicon_data(h);
if (hash_add(cdat, "xml-changelog", &xchlog, sizeof(xchlog))==NULL)
return -1;
return 0;
}
/*! Get user clicon command-line options argv, argc (after --)
* @param[in] h Clicon handle
* @param[out] argc
* @param[out] argv
* @retval 0 OK
* @retval -1 Error
*/
int
clicon_argv_get(clicon_handle h,
int *argc,
char ***argv)
{
clicon_hash_t *cdat = clicon_data(h);
void *p;
if ((p = hash_value(cdat, "argc", NULL)) == NULL)
return -1;
*argc = *(int*)p;
if ((p = hash_value(cdat, "argv", NULL)) == NULL)
return -1;
*argv = *(char***)p;
return 0;
}
/*! Set clicon user command-line options argv, argc (after --)
* @param[in] h Clicon handle
* @param[in] prog argv[0] - the program name
* @param[in] argc Length of argv
* @param[in] argv Array of command-line options
* @retval 0 OK
* @retval -1 Error
*/
int
clicon_argv_set(clicon_handle h,
char *prgm,
int argc,
char **argv)
{
clicon_hash_t *cdat = clicon_data(h);
char **argvv = NULL;
/* add space for null-termination and argv[0] program name */
if ((argvv = calloc(argc+2, sizeof(char*))) == NULL){
clicon_err(OE_UNIX, errno, "calloc");
return -1;
}
memcpy(argvv+1, argv, argc*sizeof(char*));
argvv[0] = prgm;
if (hash_add(cdat, "argv", &argvv, sizeof(argvv))==NULL)
return -1;
argc += 1;
if (hash_add(cdat, "argc", &argc, sizeof(argc))==NULL)
return -1;
return 0;
}