Merge branch 'develop' for 3.7.0
This commit is contained in:
commit
728671944f
129 changed files with 8192 additions and 2282 deletions
101
CHANGELOG.md
101
CHANGELOG.md
|
|
@ -1,5 +1,104 @@
|
||||||
# Clixon Changelog
|
# Clixon Changelog
|
||||||
|
|
||||||
|
## 3.7.0 (22 July 2018)
|
||||||
|
|
||||||
|
### Major New features
|
||||||
|
|
||||||
|
* YANG "must" and "when" Xpath-basedconstraints according to RFC 7950 Sec 7.5.3 and 7.21.5.
|
||||||
|
* Must and when Xpath constrained checked at validation/commit.
|
||||||
|
* YANG "identity" and "identityref", according to RFC 7950 Sec 7.18 and 9.10.
|
||||||
|
* Identities checked at validation/commit.
|
||||||
|
* CLI completion support of identity values.
|
||||||
|
* Example extended with iana-if-type RFC 7224 interface identities.
|
||||||
|
* Improved support for XPATH 1.0 according to https://www.w3.org/TR/xpath-10 using yacc/lex,
|
||||||
|
* Full suport of boolean constraints for "when"/"must", not only nodesets.
|
||||||
|
* See also API changes below.
|
||||||
|
* CDATA XML support (patch by David Cornejo, Netgate)
|
||||||
|
* Encode and decode (parsing) support
|
||||||
|
* Added cligen variable translation. Useful for processing input such as hashing, encryption.
|
||||||
|
* More info in example and FAQ.
|
||||||
|
* Example:
|
||||||
|
```
|
||||||
|
cli> translate value HAL
|
||||||
|
cli> show configuration
|
||||||
|
translate {
|
||||||
|
value IBM;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
### API changes on existing features (you may need to change your code)
|
||||||
|
|
||||||
|
* YANG identity, identityref, must, and when validation support may cause applications that had not strictly enforced identities and constraints before.
|
||||||
|
* Restconf operations changed from prefix to module name.
|
||||||
|
* Proper specification for an operation is POST /restconf/operations/<module_name>:<rpc_procedure> HTTP/1.1
|
||||||
|
* See https://github.com/clicon/clixon/issues/31, https://github.com/clicon/clixon/pull/32 and https://github.com/clicon/clixon/issues/30
|
||||||
|
* Thanks David Cornejo and Dmitry Vakhrushev of Netgate for pointing this out.
|
||||||
|
* New XPATH 1.0 leads to some API changes and corrections
|
||||||
|
* Due to an error in the previous implementation, all XPATH calls on the form `x[a=str]` where `str` is a string (not a number or XML symbol), must be changed to: `x[a='str'] or x[a="str"]`
|
||||||
|
* This includes all calls to `xpath_vec, xpath_first`, etc.
|
||||||
|
* In CLI specs, calls to cli_copy_config() must change 2nd argument from `x[%s=%s]` to `x[%s='%s']`
|
||||||
|
* In CLI specs, calls to cli_show_config() may need to change third argument, eg
|
||||||
|
* `cli_show_config("running","text","/profile[name=%s]","name")` to `cli_show_config("running","text","/profile[name='%s']","name")`
|
||||||
|
* xpath_each() is removed
|
||||||
|
* The old API can be enabled by setting COMPAT_XSL in include/clixon_custom.h and recompile.
|
||||||
|
|
||||||
|
* Makefile change: Removed the make include file: clixon.mk and clixon.mk.in
|
||||||
|
* These generated the Makefile variables: clixon_DBSPECDIR, clixon_SYSCONFDIR, clixon_LOCALSTATEDIR, clixon_LIBDIR, clixon_DATADIR which have been replaced by generic autoconf variables instead.
|
||||||
|
|
||||||
|
* Removed cli callback vector functions. Set COMPAT_CLIV if you need to keep these functions in include/clixon_custom.h.
|
||||||
|
* Replace functions as follows in CLI SPEC files:
|
||||||
|
* cli_setv --> cli_set
|
||||||
|
* cli_mergev --> cli_merge
|
||||||
|
* cli_delv --> cli_del
|
||||||
|
* cli_debug_cliv --> cli_debug_cli
|
||||||
|
* cli_debug_backendv --> cli_debug_backend
|
||||||
|
* cli_set_modev --> cli_set_mode
|
||||||
|
* cli_start_shellv --> cli_start_shell
|
||||||
|
* cli_quitv --> cli_quit
|
||||||
|
* cli_commitv --> cli_commit
|
||||||
|
* cli_validatev --> cli_validate
|
||||||
|
* compare_dbsv --> compare_dbs
|
||||||
|
* load_config_filev --> load_config_file
|
||||||
|
* save_config_filev --> save_config_file
|
||||||
|
* delete_allv --> delete_all
|
||||||
|
* discard_changesv --> discard_changes
|
||||||
|
* cli_notifyv --> cli_notify
|
||||||
|
* show_yangv --> show_yang
|
||||||
|
* show_confv_xpath --> show_conf_xpath
|
||||||
|
|
||||||
|
* Changed `plugin_init()` backend return semantics: If returns NULL, _without_ calling clicon_err(), the module is disabled.
|
||||||
|
|
||||||
|
### Minor changes
|
||||||
|
|
||||||
|
* Clixon docker upgrade
|
||||||
|
* Updated the docker image build and example to a single clixon docker image.
|
||||||
|
* Example pushed to https://hub.docker.com/r/olofhagsand/clixon_example/
|
||||||
|
* Added systemd example files under example/systemd
|
||||||
|
* Added util subdir, with dedicated standalone xml, json, yang and xpath parser utility test programs.
|
||||||
|
* Validation of yang bits type space-separated list value
|
||||||
|
* Added -U <user> command line to clixon_cli and clixon_netconf for changing user.
|
||||||
|
* This is primarily for NACM pseudo-user tests
|
||||||
|
* Added a generated CLI show command that works on the generated parse tree with auto completion.
|
||||||
|
* A typical call is: show @datamodel:example, cli_show_auto("candidate", "json");
|
||||||
|
* The example contains a more elaborate example.
|
||||||
|
* Thanks ngashok for request, see https://github.com/clicon/clixon/issues/24
|
||||||
|
* Added XML namespace (xmlns) validation
|
||||||
|
* for eg <a xmlns:x="uri"><x:b/></a>
|
||||||
|
* ./configure extended with --enable-debug flag
|
||||||
|
* CFLAGS=-g ./configure deprecated
|
||||||
|
|
||||||
|
### Corrected Bugs
|
||||||
|
* Prefix of rpc was ignored (thanks Dmitri at netgate)
|
||||||
|
* https://github.com/clicon/clixon/issues/30
|
||||||
|
* Added cli return value also for single commands (eg -1)
|
||||||
|
* Fixed JSON unbalanced braces resulting in assert.
|
||||||
|
|
||||||
|
### Known issues
|
||||||
|
* Namespace name relabeling is not supported.
|
||||||
|
* Eg: if "des" is defined as prefix for an imported module, then a relabeling using xmlfns is not supported, such as:
|
||||||
|
```
|
||||||
|
<crypto xmlns:x="urn:example:des">x:des3</crypto>
|
||||||
|
```
|
||||||
|
|
||||||
## 3.6.1 (29 May 2018)
|
## 3.6.1 (29 May 2018)
|
||||||
|
|
||||||
### Corrected Bugs
|
### Corrected Bugs
|
||||||
|
|
@ -452,7 +551,7 @@ If you submit "nopresence" without a leaf, it will automatically be removed:
|
||||||
Instead use the rpc calls in clixon_proto_client.[ch]
|
Instead use the rpc calls in clixon_proto_client.[ch]
|
||||||
In clients (eg cli/netconf) replace xmldb_get() in client code with
|
In clients (eg cli/netconf) replace xmldb_get() in client code with
|
||||||
clicon_rpc_get_config().
|
clicon_rpc_get_config().
|
||||||
pIf you use the vector arguments of xmldb_get(), replace as follows:
|
If you use the vector arguments of xmldb_get(), replace as follows:
|
||||||
xmldb_get(h, db, api_path, &xt, &xvec, &xlen);
|
xmldb_get(h, db, api_path, &xt, &xvec, &xlen);
|
||||||
with
|
with
|
||||||
clicon_rpc_get_config(h, dbstr, api_path, &xt);
|
clicon_rpc_get_config(h, dbstr, api_path, &xt);
|
||||||
|
|
|
||||||
14
Makefile.in
14
Makefile.in
|
|
@ -52,11 +52,11 @@ INSTALL = @INSTALL@
|
||||||
INCLUDES = -I. -I@srcdir@ @INCLUDES@
|
INCLUDES = -I. -I@srcdir@ @INCLUDES@
|
||||||
SHELL = /bin/sh
|
SHELL = /bin/sh
|
||||||
|
|
||||||
SUBDIRS = lib apps include etc datastore yang
|
SUBDIRS = lib apps include etc datastore util yang
|
||||||
|
|
||||||
.PHONY: doc all clean depend $(SUBDIRS) install loc TAGS .config.status docker
|
.PHONY: doc all clean depend $(SUBDIRS) install loc TAGS .config.status docker
|
||||||
|
|
||||||
all: $(SUBDIRS) clixon.mk
|
all: $(SUBDIRS)
|
||||||
|
|
||||||
$(SUBDIRS):
|
$(SUBDIRS):
|
||||||
(cd $@ && $(MAKE) $(MFLAGS) all)
|
(cd $@ && $(MAKE) $(MFLAGS) all)
|
||||||
|
|
@ -65,12 +65,7 @@ depend:
|
||||||
for i in $(SUBDIRS) doc example docker; \
|
for i in $(SUBDIRS) doc example docker; \
|
||||||
do (cd $$i && $(MAKE) $(MFLAGS) depend); done
|
do (cd $$i && $(MAKE) $(MFLAGS) depend); done
|
||||||
|
|
||||||
clixon.mk: clixon.mk.cpp
|
install:
|
||||||
$(CPP) -P -traditional-cpp -x assembler-with-cpp -Dprefix=$(prefix) -Dlocalstatedir=$(localstatedir) -Dsysconfdir=$(sysconfdir) -Ddatadir=$(datadir) -Dlibdir=$(libdir) $< > $@
|
|
||||||
|
|
||||||
install: clixon.mk
|
|
||||||
install -d -m 0755 $(DESTDIR)$(datadir)/clixon
|
|
||||||
install -m 0644 clixon.mk $(DESTDIR)$(datadir)/clixon
|
|
||||||
for i in $(SUBDIRS) doc; \
|
for i in $(SUBDIRS) doc; \
|
||||||
do (cd $$i; $(MAKE) $(MFLAGS) $@)||exit 1; done; \
|
do (cd $$i; $(MAKE) $(MFLAGS) $@)||exit 1; done; \
|
||||||
echo "Install for compilation by: make install-include"
|
echo "Install for compilation by: make install-include"
|
||||||
|
|
@ -83,7 +78,6 @@ install-include:
|
||||||
uninstall:
|
uninstall:
|
||||||
for i in $(SUBDIRS) doc example docker; \
|
for i in $(SUBDIRS) doc example docker; \
|
||||||
do (cd $$i && $(MAKE) $(MFLAGS) $@)||exit 1; done;
|
do (cd $$i && $(MAKE) $(MFLAGS) $@)||exit 1; done;
|
||||||
rm -f $(DESTDIR)$(datadir)/clixon/clixon.mk
|
|
||||||
|
|
||||||
doc:
|
doc:
|
||||||
cd $@; $(MAKE) $(MFLAGS) $@
|
cd $@; $(MAKE) $(MFLAGS) $@
|
||||||
|
|
@ -100,7 +94,7 @@ clean:
|
||||||
|
|
||||||
distclean:
|
distclean:
|
||||||
rm -f Makefile TAGS config.status config.log *~ .depend
|
rm -f Makefile TAGS config.status config.log *~ .depend
|
||||||
rm -rf autom4te.cache clixon.mk build-root/rpmbuild
|
rm -rf autom4te.cache build-root/rpmbuild
|
||||||
rm -f build-root/*.tar.xz build-root/*.rpm extras/rpm/Makefile
|
rm -f build-root/*.tar.xz build-root/*.rpm extras/rpm/Makefile
|
||||||
for i in $(SUBDIRS) doc example docker; \
|
for i in $(SUBDIRS) doc example docker; \
|
||||||
do (cd $$i && $(MAKE) $(MFLAGS) $@); done
|
do (cd $$i && $(MAKE) $(MFLAGS) $@); done
|
||||||
|
|
|
||||||
17
README.md
17
README.md
|
|
@ -11,6 +11,7 @@ transaction support from a YANG specification.
|
||||||
* [Support](#support)
|
* [Support](#support)
|
||||||
* [Dependencies](#dependencies)
|
* [Dependencies](#dependencies)
|
||||||
* [Extending](#extending)
|
* [Extending](#extending)
|
||||||
|
* [XML and XPATH](#xml)
|
||||||
* [Yang](#yang)
|
* [Yang](#yang)
|
||||||
* [Netconf](#netconf)
|
* [Netconf](#netconf)
|
||||||
* [Restconf](#restconf)
|
* [Restconf](#restconf)
|
||||||
|
|
@ -21,13 +22,14 @@ transaction support from a YANG specification.
|
||||||
* [Runtime](#runtime)
|
* [Runtime](#runtime)
|
||||||
* [Clixon project page](http://www.clicon.org)
|
* [Clixon project page](http://www.clicon.org)
|
||||||
* [Tests](test/)
|
* [Tests](test/)
|
||||||
|
* [Docker](docker/)
|
||||||
* [Reference manual](http://www.clicon.org/doxygen/index.html) (Note: the link may not be up-to-date. It is better to build your own: `cd doc; make doc`)
|
* [Reference manual](http://www.clicon.org/doxygen/index.html) (Note: the link may not be up-to-date. It is better to build your own: `cd doc; make doc`)
|
||||||
|
|
||||||
Background
|
Background
|
||||||
==========
|
==========
|
||||||
|
|
||||||
Clixon was implemented to provide an open-source generic configuration
|
Clixon was implemented to provide an open-source generic configuration
|
||||||
tool. The existing [CLIgen](http://www.cligen.se) tool was for command-lines only, whilke clixon is a system with config-db, xml and rest interfaces. Most of the projects using clixon are for embedded network and measuring devices. But Clixon is more generic than that.
|
tool. The existing [CLIgen](http://www.cligen.se) tool was for command-lines only, while clixon is a system with configuration database, xml and rest interfaces. Most of the projects using clixon are for embedded network and measuring devices. But Clixon is more generic than that.
|
||||||
|
|
||||||
Users of clixon currently include:
|
Users of clixon currently include:
|
||||||
* [Netgate](https://www.netgate.com)
|
* [Netgate](https://www.netgate.com)
|
||||||
|
|
@ -89,9 +91,17 @@ are also available.
|
||||||
Plugins are written in C and easiest is to look at
|
Plugins are written in C and easiest is to look at
|
||||||
[example](example/README.md) or consulting the [FAQ](doc/FAQ.md).
|
[example](example/README.md) or consulting the [FAQ](doc/FAQ.md).
|
||||||
|
|
||||||
|
XML
|
||||||
|
===
|
||||||
|
Clixon has its own implementation of XML and XPATH implementation.
|
||||||
|
|
||||||
|
The standards covered include:
|
||||||
|
- [XML](https://www.w3.org/TR/2008/REC-xml-20081126)
|
||||||
|
- [Namespaces](https://www.w3.org/TR/2009/REC-xml-names-20091208)
|
||||||
|
- [XPATH](https://www.w3.org/TR/xpath-10)
|
||||||
|
|
||||||
Yang
|
Yang
|
||||||
====
|
====
|
||||||
|
|
||||||
YANG and XML is at the heart of Clixon. Yang modules are used as a
|
YANG and XML is at the heart of Clixon. Yang modules are used as a
|
||||||
specification for handling XML configuration data. The YANG spec is
|
specification for handling XML configuration data. The YANG spec is
|
||||||
used to generate an interactive CLI, netconf and restconf clients. It
|
used to generate an interactive CLI, netconf and restconf clients. It
|
||||||
|
|
@ -99,8 +109,9 @@ also manages an XML datastore.
|
||||||
|
|
||||||
Clixon mainly follows [YANG 1.0 RFC 6020](https://www.rfc-editor.org/rfc/rfc6020.txt) with some exceptions:
|
Clixon mainly follows [YANG 1.0 RFC 6020](https://www.rfc-editor.org/rfc/rfc6020.txt) with some exceptions:
|
||||||
- conformance: feature, if-feature, deviation
|
- conformance: feature, if-feature, deviation
|
||||||
- identity, base, identityref
|
|
||||||
- list features: min/max-elements, unique
|
- list features: min/max-elements, unique
|
||||||
|
- action statements
|
||||||
|
- notifications
|
||||||
|
|
||||||
The aim is also to cover new features in YANG 1.1 [YANG RFC 7950](https://www.rfc-editor.org/rfc/rfc7950.txt)
|
The aim is also to cover new features in YANG 1.1 [YANG RFC 7950](https://www.rfc-editor.org/rfc/rfc7950.txt)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -531,6 +531,8 @@ from_client_unlock(clicon_handle h,
|
||||||
ok:
|
ok:
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
|
if (cbx)
|
||||||
|
cbuf_free(cbx);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -803,12 +805,13 @@ from_client_debug(clicon_handle h,
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Match nacm access operations according to RFC8321 3.4.4.
|
/*! Match nacm access operations according to RFC8341 3.4.4.
|
||||||
* Incoming RPC Message Validation Step 7 (c)
|
* Incoming RPC Message Validation Step 7 (c)
|
||||||
* The rule's "access-operations" leaf has the "exec" bit set or
|
* The rule's "access-operations" leaf has the "exec" bit set or
|
||||||
* has the special value "*".
|
* has the special value "*".
|
||||||
* @retval 0 No match
|
* @retval 0 No match
|
||||||
* @retval 1 Match
|
* @retval 1 Match
|
||||||
|
* XXX access_operations is bit-fields
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
nacm_match_access(char *access_operations,
|
nacm_match_access(char *access_operations,
|
||||||
|
|
@ -818,7 +821,7 @@ nacm_match_access(char *access_operations,
|
||||||
return 0;
|
return 0;
|
||||||
if (strcmp(access_operations,"*")==0)
|
if (strcmp(access_operations,"*")==0)
|
||||||
return 1;
|
return 1;
|
||||||
if (strstr(mode, access_operations)!=NULL)
|
if (strstr(access_operations, mode)!=NULL)
|
||||||
return 1;
|
return 1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -832,7 +835,7 @@ nacm_match_access(char *access_operations,
|
||||||
* @retval 0 Matching rule AND Not access and cbret set
|
* @retval 0 Matching rule AND Not access and cbret set
|
||||||
* @retval 1 Matchung rule AND Access
|
* @retval 1 Matchung rule AND Access
|
||||||
* @retval 2 No matching rule Goto step 10
|
* @retval 2 No matching rule Goto step 10
|
||||||
* From RFC8321 3.4.4. Incoming RPC Message Validation
|
* From RFC8341 3.4.4. Incoming RPC Message Validation
|
||||||
+---------+-----------------+---------------------+-----------------+
|
+---------+-----------------+---------------------+-----------------+
|
||||||
| Method | Resource class | NETCONF operation | Access |
|
| Method | Resource class | NETCONF operation | Access |
|
||||||
| | | | operation |
|
| | | | operation |
|
||||||
|
|
@ -874,6 +877,7 @@ nacm_match_rule(clicon_handle h,
|
||||||
|
|
||||||
module_name = xml_find_body(xrule, "module-name");
|
module_name = xml_find_body(xrule, "module-name");
|
||||||
rpc_name = xml_find_body(xrule, "rpc-name");
|
rpc_name = xml_find_body(xrule, "rpc-name");
|
||||||
|
/* XXX access_operations can be a set of bits */
|
||||||
access_operations = xml_find_body(xrule, "access-operations");
|
access_operations = xml_find_body(xrule, "access-operations");
|
||||||
action = xml_find_body(xrule, "action");
|
action = xml_find_body(xrule, "action");
|
||||||
clicon_debug(1, "%s: %s %s %s %s", __FUNCTION__,
|
clicon_debug(1, "%s: %s %s %s %s", __FUNCTION__,
|
||||||
|
|
@ -911,7 +915,7 @@ nacm_match_rule(clicon_handle h,
|
||||||
* @retval -1 Error
|
* @retval -1 Error
|
||||||
* @retval 0 Not access and cbret set
|
* @retval 0 Not access and cbret set
|
||||||
* @retval 1 Access
|
* @retval 1 Access
|
||||||
* From RFC8321 3.4.4. Incoming RPC Message Validation
|
* From RFC8341 3.4.4. Incoming RPC Message Validation
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
nacm_access(clicon_handle h,
|
nacm_access(clicon_handle h,
|
||||||
|
|
@ -983,7 +987,13 @@ nacm_access(clicon_handle h,
|
||||||
if (username == NULL)
|
if (username == NULL)
|
||||||
goto step10;
|
goto step10;
|
||||||
/* User's group */
|
/* User's group */
|
||||||
if (xpath_vec(xacm, "groups/group[user-name=%s]", &gvec, &glen, username) < 0)
|
if (xpath_vec(xacm,
|
||||||
|
#ifdef COMPAT_XSL
|
||||||
|
"groups/group[user-name=%s]",
|
||||||
|
#else
|
||||||
|
"groups/group[user-name='%s']",
|
||||||
|
#endif
|
||||||
|
&gvec, &glen, username) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
/* 5. If no groups are found, continue with step 10. */
|
/* 5. If no groups are found, continue with step 10. */
|
||||||
if (glen == 0)
|
if (glen == 0)
|
||||||
|
|
@ -1000,7 +1010,13 @@ nacm_access(clicon_handle h,
|
||||||
for (j=0; j<glen; j++){
|
for (j=0; j<glen; j++){
|
||||||
char *gname;
|
char *gname;
|
||||||
gname = xml_find_body(gvec[j], "name");
|
gname = xml_find_body(gvec[j], "name");
|
||||||
if (xpath_first(xrlist,".[group=%s]", gname)!=NULL)
|
if (xpath_first(xrlist,
|
||||||
|
#ifdef COMPAT_XSL
|
||||||
|
".[group=%s]",
|
||||||
|
#else
|
||||||
|
".[group='%s']",
|
||||||
|
#endif
|
||||||
|
gname)!=NULL)
|
||||||
break; /* found */
|
break; /* found */
|
||||||
}
|
}
|
||||||
if (j==glen) /* not found */
|
if (j==glen) /* not found */
|
||||||
|
|
@ -1202,7 +1218,7 @@ from_client_msg(clicon_handle h,
|
||||||
}
|
}
|
||||||
reply:
|
reply:
|
||||||
if (cbuf_len(cbret) == 0)
|
if (cbuf_len(cbret) == 0)
|
||||||
if (netconf_operation_failed(cbret, "application", clicon_err_reason)< 0)
|
if (netconf_operation_failed(cbret, "application", clicon_errno?clicon_err_reason:"unknown")< 0)
|
||||||
goto done;
|
goto done;
|
||||||
clicon_debug(1, "%s cbret:%s", __FUNCTION__, cbuf_get(cbret));
|
clicon_debug(1, "%s cbret:%s", __FUNCTION__, cbuf_get(cbret));
|
||||||
/* XXX problem here is that cbret has not been parsed so may contain
|
/* XXX problem here is that cbret has not been parsed so may contain
|
||||||
|
|
|
||||||
|
|
@ -79,8 +79,8 @@
|
||||||
* string regexp checked.
|
* string regexp checked.
|
||||||
* See also db_lv_set() where defaults are also filled in. The case here for defaults
|
* See also db_lv_set() where defaults are also filled in. The case here for defaults
|
||||||
* are if code comes via XML/NETCONF.
|
* are if code comes via XML/NETCONF.
|
||||||
* @param yspec Yang spec
|
* @param[in] yspec Yang spec
|
||||||
* @param td Transaction data
|
* @param[in] td Transaction data
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
generic_validate(yang_spec *yspec,
|
generic_validate(yang_spec *yspec,
|
||||||
|
|
|
||||||
|
|
@ -117,7 +117,8 @@ backend_sig_term(int arg)
|
||||||
/*! usage
|
/*! usage
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
usage(char *argv0, clicon_handle h)
|
usage(clicon_handle h,
|
||||||
|
char *argv0)
|
||||||
{
|
{
|
||||||
char *plgdir = clicon_backend_dir(h);
|
char *plgdir = clicon_backend_dir(h);
|
||||||
char *confsock = clicon_sock(h);
|
char *confsock = clicon_sock(h);
|
||||||
|
|
@ -581,11 +582,11 @@ main(int argc,
|
||||||
break;
|
break;
|
||||||
case 'D' : /* debug */
|
case 'D' : /* debug */
|
||||||
if (sscanf(optarg, "%d", &debug) != 1)
|
if (sscanf(optarg, "%d", &debug) != 1)
|
||||||
usage(argv[0], h);
|
usage(h, argv[0]);
|
||||||
break;
|
break;
|
||||||
case 'f': /* config file */
|
case 'f': /* config file */
|
||||||
if (!strlen(optarg))
|
if (!strlen(optarg))
|
||||||
usage(argv[0], h);
|
usage(h, argv[0]);
|
||||||
clicon_option_str_set(h, "CLICON_CONFIGFILE", optarg);
|
clicon_option_str_set(h, "CLICON_CONFIGFILE", optarg);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -602,7 +603,7 @@ main(int argc,
|
||||||
/* Find and read configfile */
|
/* Find and read configfile */
|
||||||
if (clicon_options_main(h) < 0){
|
if (clicon_options_main(h) < 0){
|
||||||
if (help)
|
if (help)
|
||||||
usage(argv[0], h);
|
usage(h, argv[0]);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
/* External NACM file? */
|
/* External NACM file? */
|
||||||
|
|
@ -621,12 +622,12 @@ main(int argc,
|
||||||
break; /* see above */
|
break; /* see above */
|
||||||
case 'd': /* Plugin directory */
|
case 'd': /* Plugin directory */
|
||||||
if (!strlen(optarg))
|
if (!strlen(optarg))
|
||||||
usage(argv[0], h);
|
usage(h, argv[0]);
|
||||||
clicon_option_str_set(h, "CLICON_BACKEND_DIR", optarg);
|
clicon_option_str_set(h, "CLICON_BACKEND_DIR", optarg);
|
||||||
break;
|
break;
|
||||||
case 'b': /* XMLDB database directory */
|
case 'b': /* XMLDB database directory */
|
||||||
if (!strlen(optarg))
|
if (!strlen(optarg))
|
||||||
usage(argv[0], h);
|
usage(h, argv[0]);
|
||||||
clicon_option_str_set(h, "CLICON_XMLDB_DIR", optarg);
|
clicon_option_str_set(h, "CLICON_XMLDB_DIR", optarg);
|
||||||
break;
|
break;
|
||||||
case 'F' : /* foreground */
|
case 'F' : /* foreground */
|
||||||
|
|
@ -640,7 +641,7 @@ main(int argc,
|
||||||
break;
|
break;
|
||||||
case 'u': /* config unix domain path / ip address */
|
case 'u': /* config unix domain path / ip address */
|
||||||
if (!strlen(optarg))
|
if (!strlen(optarg))
|
||||||
usage(argv[0], h);
|
usage(h, argv[0]);
|
||||||
clicon_option_str_set(h, "CLICON_SOCK", optarg);
|
clicon_option_str_set(h, "CLICON_SOCK", optarg);
|
||||||
break;
|
break;
|
||||||
case 'P': /* pidfile */
|
case 'P': /* pidfile */
|
||||||
|
|
@ -650,7 +651,7 @@ main(int argc,
|
||||||
clicon_option_str_set(h, "CLICON_STARTUP_MODE", optarg);
|
clicon_option_str_set(h, "CLICON_STARTUP_MODE", optarg);
|
||||||
if (clicon_startup_mode(h) < 0){
|
if (clicon_startup_mode(h) < 0){
|
||||||
fprintf(stderr, "Invalid startup mode: %s\n", optarg);
|
fprintf(stderr, "Invalid startup mode: %s\n", optarg);
|
||||||
usage(argv[0], h);
|
usage(h, argv[0]);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'c': /* Load application config */
|
case 'c': /* Load application config */
|
||||||
|
|
@ -668,7 +669,7 @@ main(int argc,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
usage(argv[0], h);
|
usage(h, argv[0]);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -677,7 +678,7 @@ main(int argc,
|
||||||
|
|
||||||
/* Defer: Wait to the last minute to print help message */
|
/* Defer: Wait to the last minute to print help message */
|
||||||
if (help)
|
if (help)
|
||||||
usage(argv[0], h);
|
usage(h, argv[0]);
|
||||||
|
|
||||||
/* Check pid-file, if zap kil the old daemon, else return here */
|
/* Check pid-file, if zap kil the old daemon, else return here */
|
||||||
if ((pidfile = clicon_backend_pidfile(h)) == NULL){
|
if ((pidfile = clicon_backend_pidfile(h)) == NULL){
|
||||||
|
|
|
||||||
|
|
@ -157,6 +157,8 @@ clixon_plugin_statedata(clicon_handle h,
|
||||||
if (reason){
|
if (reason){
|
||||||
while ((xc = xml_child_i(*xtop, 0)) != NULL)
|
while ((xc = xml_child_i(*xtop, 0)) != NULL)
|
||||||
xml_purge(xc);
|
xml_purge(xc);
|
||||||
|
clicon_log(LOG_NOTICE, "%s: Plugin '%s' state callback failed",
|
||||||
|
__FUNCTION__, cp->cp_name);
|
||||||
if (netconf_operation_failed_xml(xtop, "rpc", reason)< 0)
|
if (netconf_operation_failed_xml(xtop, "rpc", reason)< 0)
|
||||||
goto done;
|
goto done;
|
||||||
goto ok;
|
goto ok;
|
||||||
|
|
@ -167,7 +169,7 @@ clixon_plugin_statedata(clicon_handle h,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Code complex to filter out anything that is outside of xpath */
|
/* Code complex to filter out anything that is outside of xpath */
|
||||||
if (xpath_vec(*xtop, xpath?xpath:"/", &xvec, &xlen) < 0)
|
if (xpath_vec(*xtop, "%s", &xvec, &xlen, xpath?xpath:"/") < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
/* If vectors are specified then mark the nodes found and
|
/* If vectors are specified then mark the nodes found and
|
||||||
|
|
|
||||||
|
|
@ -96,12 +96,12 @@ config_socket_init_ipv4(clicon_handle h, char *dst)
|
||||||
goto err; /* Could check getaddrinfo */
|
goto err; /* Could check getaddrinfo */
|
||||||
}
|
}
|
||||||
if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0){
|
if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0){
|
||||||
clicon_err(OE_UNIX, errno, "%s: bind", __FUNCTION__);
|
clicon_err(OE_UNIX, errno, "bind");
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
clicon_debug(1, "Listen on server socket at %s:%hu", dst, port);
|
clicon_debug(1, "Listen on server socket at %s:%hu", dst, port);
|
||||||
if (listen(s, 5) < 0){
|
if (listen(s, 5) < 0){
|
||||||
clicon_err(OE_UNIX, errno, "%s: listen", __FUNCTION__);
|
clicon_err(OE_UNIX, errno, "listen");
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
return s;
|
return s;
|
||||||
|
|
@ -126,7 +126,7 @@ config_socket_init_unix(clicon_handle h, char *sock)
|
||||||
struct stat st;
|
struct stat st;
|
||||||
|
|
||||||
if (lstat(sock, &st) == 0 && unlink(sock) < 0){
|
if (lstat(sock, &st) == 0 && unlink(sock) < 0){
|
||||||
clicon_err(OE_UNIX, errno, "%s: unlink(%s)", __FUNCTION__, sock);
|
clicon_err(OE_UNIX, errno, "unlink(%s)", sock);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
/* then find configuration group (for clients) and find its groupid */
|
/* then find configuration group (for clients) and find its groupid */
|
||||||
|
|
@ -142,7 +142,7 @@ config_socket_init_unix(clicon_handle h, char *sock)
|
||||||
#endif
|
#endif
|
||||||
/* create unix socket */
|
/* create unix socket */
|
||||||
if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
|
if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
|
||||||
clicon_err(OE_UNIX, errno, "%s: socket", __FUNCTION__);
|
clicon_err(OE_UNIX, errno, "socket");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
// setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (void*)&one, sizeof(one));
|
// setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (void*)&one, sizeof(one));
|
||||||
|
|
@ -151,20 +151,19 @@ config_socket_init_unix(clicon_handle h, char *sock)
|
||||||
strncpy(addr.sun_path, sock, sizeof(addr.sun_path)-1);
|
strncpy(addr.sun_path, sock, sizeof(addr.sun_path)-1);
|
||||||
old_mask = umask(S_IRWXO | S_IXGRP | S_IXUSR);
|
old_mask = umask(S_IRWXO | S_IXGRP | S_IXUSR);
|
||||||
if (bind(s, (struct sockaddr *)&addr, SUN_LEN(&addr)) < 0){
|
if (bind(s, (struct sockaddr *)&addr, SUN_LEN(&addr)) < 0){
|
||||||
clicon_err(OE_UNIX, errno, "%s: bind", __FUNCTION__);
|
clicon_err(OE_UNIX, errno, "bind");
|
||||||
umask(old_mask);
|
umask(old_mask);
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
umask(old_mask);
|
umask(old_mask);
|
||||||
/* change socket path file group */
|
/* change socket path file group */
|
||||||
if (lchown(sock, -1, gid) < 0){
|
if (lchown(sock, -1, gid) < 0){
|
||||||
clicon_err(OE_UNIX, errno, "%s: lchown(%s, %s)", __FUNCTION__,
|
clicon_err(OE_UNIX, errno, "lchown(%s, %s)", sock, config_group);
|
||||||
sock, config_group);
|
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
clicon_debug(1, "Listen on server socket at %s", addr.sun_path);
|
clicon_debug(1, "Listen on server socket at %s", addr.sun_path);
|
||||||
if (listen(s, 5) < 0){
|
if (listen(s, 5) < 0){
|
||||||
clicon_err(OE_UNIX, errno, "%s: listen", __FUNCTION__);
|
clicon_err(OE_UNIX, errno, "listen");
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
return s;
|
return s;
|
||||||
|
|
@ -221,14 +220,14 @@ backend_accept_client(int fd,
|
||||||
clicon_debug(2, "%s", __FUNCTION__);
|
clicon_debug(2, "%s", __FUNCTION__);
|
||||||
len = sizeof(from);
|
len = sizeof(from);
|
||||||
if ((s = accept(fd, (struct sockaddr*)&from, &len)) < 0){
|
if ((s = accept(fd, (struct sockaddr*)&from, &len)) < 0){
|
||||||
clicon_err(OE_UNIX, errno, "%s: accept", __FUNCTION__);
|
clicon_err(OE_UNIX, errno, "accept");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
#if defined(SO_PEERCRED)
|
#if defined(SO_PEERCRED)
|
||||||
/* fill in the user data structure */
|
/* fill in the user data structure */
|
||||||
clen = sizeof(credentials);
|
clen = sizeof(credentials);
|
||||||
if(getsockopt(s, SOL_SOCKET, SO_PEERCRED/* XXX finns ej i freebsd*/, &credentials, &clen)){
|
if(getsockopt(s, SOL_SOCKET, SO_PEERCRED/* XXX finns ej i freebsd*/, &credentials, &clen)){
|
||||||
clicon_err(OE_UNIX, errno, "%s: getsockopt", __FUNCTION__);
|
clicon_err(OE_UNIX, errno, "getsockopt");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -220,7 +220,7 @@ backend_notify_xml(clicon_handle h,
|
||||||
ce_next = ce->ce_next;
|
ce_next = ce->ce_next;
|
||||||
for (su = ce->ce_subscription; su; su = su->su_next)
|
for (su = ce->ce_subscription; su; su = su->su_next)
|
||||||
if (strcmp(su->su_stream, stream) == 0){
|
if (strcmp(su->su_stream, stream) == 0){
|
||||||
if (strlen(su->su_filter)==0 || xpath_first(x, su->su_filter) != NULL){
|
if (strlen(su->su_filter)==0 || xpath_first(x, "%s", su->su_filter) != NULL){
|
||||||
if (cb==NULL){
|
if (cb==NULL){
|
||||||
if ((cb = cbuf_new()) == NULL){
|
if ((cb = cbuf_new()) == NULL){
|
||||||
clicon_err(OE_PLUGIN, errno, "cbuf_new");
|
clicon_err(OE_PLUGIN, errno, "cbuf_new");
|
||||||
|
|
@ -255,7 +255,7 @@ backend_notify_xml(clicon_handle h,
|
||||||
continue;
|
continue;
|
||||||
if (strcmp(hs->hs_stream, stream))
|
if (strcmp(hs->hs_stream, stream))
|
||||||
continue;
|
continue;
|
||||||
if (strlen(hs->hs_filter)==0 || xpath_first(x, hs->hs_filter) != NULL){
|
if (strlen(hs->hs_filter)==0 || xpath_first(x, "%s", hs->hs_filter) != NULL){
|
||||||
if ((*hs->hs_fn)(h, x, hs->hs_arg) < 0)
|
if ((*hs->hs_fn)(h, x, hs->hs_arg) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -78,7 +78,7 @@
|
||||||
/*! Register log notification stream
|
/*! Register log notification stream
|
||||||
* @param[in] h Clicon handle
|
* @param[in] h Clicon handle
|
||||||
* @param[in] stream Event stream. CLICON is predefined, others are application-defined
|
* @param[in] stream Event stream. CLICON is predefined, others are application-defined
|
||||||
* @param[in] filter Filter. For xml notification ie xpath: .[name=kalle]
|
* @param[in] filter Filter. For xml notification ie xpath: .[name="kalle"]
|
||||||
* @param[in] status 0 for stop, 1 to start
|
* @param[in] status 0 for stop, 1 to start
|
||||||
* @param[in] fn Callback function called when notification occurs
|
* @param[in] fn Callback function called when notification occurs
|
||||||
* @param[in] arg Argument to function note
|
* @param[in] arg Argument to function note
|
||||||
|
|
@ -184,7 +184,7 @@ cli_signal_flush(clicon_handle h)
|
||||||
cli_signal_block (h);
|
cli_signal_block (h);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Modify xml database from a callback using xml key format strings
|
/*! Modify xml datastore from a callback using xml key format strings
|
||||||
* @param[in] h Clicon handle
|
* @param[in] h Clicon handle
|
||||||
* @param[in] cvv Vector of cli string and instantiated variables
|
* @param[in] cvv Vector of cli string and instantiated variables
|
||||||
* @param[in] argv Vector. First element xml key format string, eg "/aaa/%s"
|
* @param[in] argv Vector. First element xml key format string, eg "/aaa/%s"
|
||||||
|
|
@ -221,7 +221,7 @@ cli_dbxml(clicon_handle h,
|
||||||
cxobj *xb; /* body */
|
cxobj *xb; /* body */
|
||||||
|
|
||||||
if (cvec_len(argv) != 1){
|
if (cvec_len(argv) != 1){
|
||||||
clicon_err(OE_PLUGIN, 0, "%s: Requires one element to be xml key format string", __FUNCTION__);
|
clicon_err(OE_PLUGIN, 0, "Requires one element to be xml key format string");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if ((yspec = clicon_dbspec_yang(h)) == NULL){
|
if ((yspec = clicon_dbspec_yang(h)) == NULL){
|
||||||
|
|
@ -283,8 +283,15 @@ cli_dbxml(clicon_handle h,
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! Set datastore xml entry
|
||||||
|
* @param[in] h Clicon handle
|
||||||
|
* @param[in] cvv Vector of cli string and instantiated variables
|
||||||
|
* @param[in] argv Vector. First element xml key format string, eg "/aaa/%s"
|
||||||
|
*/
|
||||||
int
|
int
|
||||||
cli_set(clicon_handle h, cvec *cvv, cvec *argv)
|
cli_set(clicon_handle h,
|
||||||
|
cvec *cvv,
|
||||||
|
cvec *argv)
|
||||||
{
|
{
|
||||||
int retval = 1;
|
int retval = 1;
|
||||||
|
|
||||||
|
|
@ -294,13 +301,16 @@ cli_set(clicon_handle h, cvec *cvv, cvec *argv)
|
||||||
done:
|
done:
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
int cli_setv(clicon_handle h, cvec *vars, cvec *argv)
|
|
||||||
{
|
|
||||||
return cli_set(h, vars, argv);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/*! Merge datastore xml entry
|
||||||
|
* @param[in] h Clicon handle
|
||||||
|
* @param[in] cvv Vector of cli string and instantiated variables
|
||||||
|
* @param[in] argv Vector. First element xml key format string, eg "/aaa/%s"
|
||||||
|
*/
|
||||||
int
|
int
|
||||||
cli_merge(clicon_handle h, cvec *cvv, cvec *argv)
|
cli_merge(clicon_handle h,
|
||||||
|
cvec *cvv,
|
||||||
|
cvec *argv)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
|
|
||||||
|
|
@ -310,13 +320,16 @@ cli_merge(clicon_handle h, cvec *cvv, cvec *argv)
|
||||||
done:
|
done:
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
int cli_mergev(clicon_handle h, cvec *vars, cvec *argv)
|
|
||||||
{
|
|
||||||
return cli_merge(h, vars, argv);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/*! Create datastore xml entry
|
||||||
|
* @param[in] h Clicon handle
|
||||||
|
* @param[in] cvv Vector of cli string and instantiated variables
|
||||||
|
* @param[in] argv Vector. First element xml key format string, eg "/aaa/%s"
|
||||||
|
*/
|
||||||
int
|
int
|
||||||
cli_create(clicon_handle h, cvec *cvv, cvec *argv)
|
cli_create(clicon_handle h,
|
||||||
|
cvec *cvv,
|
||||||
|
cvec *argv)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
|
|
||||||
|
|
@ -326,11 +339,16 @@ cli_create(clicon_handle h, cvec *cvv, cvec *argv)
|
||||||
done:
|
done:
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
/*!
|
/*! Remove datastore xml entry
|
||||||
|
* @param[in] h Clicon handle
|
||||||
|
* @param[in] cvv Vector of cli string and instantiated variables
|
||||||
|
* @param[in] argv Vector. First element xml key format string, eg "/aaa/%s"
|
||||||
* @see cli_del
|
* @see cli_del
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
cli_remove(clicon_handle h, cvec *cvv, cvec *argv)
|
cli_remove(clicon_handle h,
|
||||||
|
cvec *cvv,
|
||||||
|
cvec *argv)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
|
|
||||||
|
|
@ -341,8 +359,15 @@ cli_remove(clicon_handle h, cvec *cvv, cvec *argv)
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! Delete datastore xml
|
||||||
|
* @param[in] h Clicon handle
|
||||||
|
* @param[in] cvv Vector of cli string and instantiated variables
|
||||||
|
* @param[in] argv Vector. First element xml key format string, eg "/aaa/%s"
|
||||||
|
*/
|
||||||
int
|
int
|
||||||
cli_del(clicon_handle h, cvec *cvv, cvec *argv)
|
cli_del(clicon_handle h,
|
||||||
|
cvec *cvv,
|
||||||
|
cvec *argv)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
|
|
||||||
|
|
@ -352,11 +377,6 @@ cli_del(clicon_handle h, cvec *cvv, cvec *argv)
|
||||||
done:
|
done:
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
int cli_delv(clicon_handle h, cvec *vars, cvec *argv)
|
|
||||||
{
|
|
||||||
return cli_del(h, vars, argv);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*! Set debug level on CLI client (not backend daemon)
|
/*! Set debug level on CLI client (not backend daemon)
|
||||||
* @param[in] h Clicon handle
|
* @param[in] h Clicon handle
|
||||||
|
|
@ -374,9 +394,9 @@ cli_debug_cli(clicon_handle h,
|
||||||
cg_var *cv;
|
cg_var *cv;
|
||||||
int level;
|
int level;
|
||||||
|
|
||||||
if ((cv = cvec_find_var(vars, "level")) == NULL){
|
if ((cv = cvec_find(vars, "level")) == NULL){
|
||||||
if (cvec_len(argv) != 1){
|
if (cvec_len(argv) != 1){
|
||||||
clicon_err(OE_PLUGIN, 0, "%s: Requires either label var or single arg: 0|1", __FUNCTION__);
|
clicon_err(OE_PLUGIN, 0, "Requires either label var or single arg: 0|1");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
cv = cvec_i(argv, 0);
|
cv = cvec_i(argv, 0);
|
||||||
|
|
@ -388,10 +408,6 @@ cli_debug_cli(clicon_handle h,
|
||||||
done:
|
done:
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
int cli_debug_cliv(clicon_handle h, cvec *vars, cvec *argv)
|
|
||||||
{
|
|
||||||
return cli_debug_cli(h, vars, argv);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! Set debug level on backend daemon (not CLI)
|
/*! Set debug level on backend daemon (not CLI)
|
||||||
* @param[in] h Clicon handle
|
* @param[in] h Clicon handle
|
||||||
|
|
@ -409,9 +425,9 @@ cli_debug_backend(clicon_handle h,
|
||||||
cg_var *cv;
|
cg_var *cv;
|
||||||
int level;
|
int level;
|
||||||
|
|
||||||
if ((cv = cvec_find_var(vars, "level")) == NULL){
|
if ((cv = cvec_find(vars, "level")) == NULL){
|
||||||
if (cvec_len(argv) != 1){
|
if (cvec_len(argv) != 1){
|
||||||
clicon_err(OE_PLUGIN, 0, "%s: Requires either label var or single arg: 0|1", __FUNCTION__);
|
clicon_err(OE_PLUGIN, 0, "Requires either label var or single arg: 0|1");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
cv = cvec_i(argv, 0);
|
cv = cvec_i(argv, 0);
|
||||||
|
|
@ -422,11 +438,39 @@ cli_debug_backend(clicon_handle h,
|
||||||
done:
|
done:
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
int cli_debug_backendv(clicon_handle h, cvec *vars, cvec *argv)
|
|
||||||
|
/*! Set debug level on restconf daemon
|
||||||
|
* @param[in] h Clicon handle
|
||||||
|
* @param[in] vars If variable "level" exists, its integer value is used
|
||||||
|
* @param[in] arg Else use the integer value of argument
|
||||||
|
* @note The level is either what is specified in arg as int argument.
|
||||||
|
* _or_ if a 'level' variable is present in vars use that value instead.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
cli_debug_restconf(clicon_handle h,
|
||||||
|
cvec *vars,
|
||||||
|
cvec *argv)
|
||||||
{
|
{
|
||||||
return cli_debug_backend(h, vars, argv);
|
int retval = -1;
|
||||||
|
cg_var *cv;
|
||||||
|
int level;
|
||||||
|
|
||||||
|
if ((cv = cvec_find(vars, "level")) == NULL){
|
||||||
|
if (cvec_len(argv) != 1){
|
||||||
|
clicon_err(OE_PLUGIN, 0, "Requires either label var or single arg: 0|1");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
cv = cvec_i(argv, 0);
|
||||||
|
}
|
||||||
|
level = cv_int32_get(cv);
|
||||||
|
/* restconf daemon */
|
||||||
|
if (0) /* XXX notyet */
|
||||||
|
retval = clicon_rpc_debug(h, level);
|
||||||
|
done:
|
||||||
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*! Set syntax mode
|
/*! Set syntax mode
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
|
|
@ -438,7 +482,7 @@ cli_set_mode(clicon_handle h,
|
||||||
char *str = NULL;
|
char *str = NULL;
|
||||||
|
|
||||||
if (cvec_len(argv) != 1){
|
if (cvec_len(argv) != 1){
|
||||||
clicon_err(OE_PLUGIN, 0, "%s: Requires one element to be cli mode", __FUNCTION__);
|
clicon_err(OE_PLUGIN, 0, "Requires one element to be cli mode");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
str = cv_string_get(cvec_i(argv, 0));
|
str = cv_string_get(cvec_i(argv, 0));
|
||||||
|
|
@ -447,13 +491,10 @@ cli_set_mode(clicon_handle h,
|
||||||
done:
|
done:
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
int cli_set_modev(clicon_handle h, cvec *vars, cvec *argv)
|
|
||||||
{
|
|
||||||
return cli_set_mode(h, vars, argv);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! Start bash from cli callback
|
/*! Start bash from cli callback
|
||||||
* XXX Application specific??
|
* XXX Application specific??
|
||||||
|
* XXX replace fprintf with clicon_err?
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
cli_start_shell(clicon_handle h,
|
cli_start_shell(clicon_handle h,
|
||||||
|
|
@ -470,7 +511,7 @@ cli_start_shell(clicon_handle h,
|
||||||
|
|
||||||
if ((pw = getpwuid(getuid())) == NULL){
|
if ((pw = getpwuid(getuid())) == NULL){
|
||||||
fprintf(stderr, "%s: getpwuid: %s\n",
|
fprintf(stderr, "%s: getpwuid: %s\n",
|
||||||
__FUNCTION__, strerror(errno));
|
__FUNCTION__, strerror(errno));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (chdir(pw->pw_dir) < 0){
|
if (chdir(pw->pw_dir) < 0){
|
||||||
|
|
@ -508,10 +549,6 @@ cli_start_shell(clicon_handle h,
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
int cli_start_shellv(clicon_handle h, cvec *vars, cvec *argv)
|
|
||||||
{
|
|
||||||
return cli_start_shell(h, vars, argv);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! Generic quit callback
|
/*! Generic quit callback
|
||||||
*/
|
*/
|
||||||
|
|
@ -523,10 +560,6 @@ cli_quit(clicon_handle h,
|
||||||
cligen_exiting_set(cli_cligen(h), 1);
|
cligen_exiting_set(cli_cligen(h), 1);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
int cli_quitv(clicon_handle h, cvec *vars, cvec *argv)
|
|
||||||
{
|
|
||||||
return cli_quit(h, vars, argv);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! Generic commit callback
|
/*! Generic commit callback
|
||||||
* @param[in] argv No arguments expected
|
* @param[in] argv No arguments expected
|
||||||
|
|
@ -544,10 +577,6 @@ cli_commit(clicon_handle h,
|
||||||
done:
|
done:
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
int cli_commitv(clicon_handle h, cvec *vars, cvec *argv)
|
|
||||||
{
|
|
||||||
return cli_commit(h, vars, argv);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! Generic validate callback
|
/*! Generic validate callback
|
||||||
*/
|
*/
|
||||||
|
|
@ -564,10 +593,6 @@ cli_validate(clicon_handle h,
|
||||||
done:
|
done:
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
int cli_validatev(clicon_handle h, cvec *vars, cvec *argv)
|
|
||||||
{
|
|
||||||
return cli_validate(h, vars, argv);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! Compare two dbs using XML. Write to file and run diff
|
/*! Compare two dbs using XML. Write to file and run diff
|
||||||
*/
|
*/
|
||||||
|
|
@ -647,7 +672,7 @@ compare_dbs(clicon_handle h,
|
||||||
int astext;
|
int astext;
|
||||||
|
|
||||||
if (cvec_len(argv) > 1){
|
if (cvec_len(argv) > 1){
|
||||||
clicon_err(OE_PLUGIN, 0, "%s: Requires 0 or 1 element. If given: astext flag 0|1", __FUNCTION__);
|
clicon_err(OE_PLUGIN, 0, "Requires 0 or 1 element. If given: astext flag 0|1");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (cvec_len(argv))
|
if (cvec_len(argv))
|
||||||
|
|
@ -677,10 +702,6 @@ compare_dbs(clicon_handle h,
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
int compare_dbsv(clicon_handle h, cvec *vars, cvec *argv)
|
|
||||||
{
|
|
||||||
return compare_dbs(h, vars, argv);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! Load a configuration file to candidate database
|
/*! Load a configuration file to candidate database
|
||||||
* Utility function used by cligen spec file
|
* Utility function used by cligen spec file
|
||||||
|
|
@ -692,7 +713,7 @@ int compare_dbsv(clicon_handle h, cvec *vars, cvec *argv)
|
||||||
* @note file is assumed to have a dummy top-tag, eg <clicon></clicon>
|
* @note file is assumed to have a dummy top-tag, eg <clicon></clicon>
|
||||||
* @code
|
* @code
|
||||||
* # cligen spec
|
* # cligen spec
|
||||||
* load file <name2:string>, load_config_filev("name2","merge");
|
* load file <name2:string>, load_config_file("name2","merge");
|
||||||
* @endcode
|
* @endcode
|
||||||
* @see save_config_file
|
* @see save_config_file
|
||||||
*/
|
*/
|
||||||
|
|
@ -730,7 +751,7 @@ load_config_file(clicon_handle h,
|
||||||
clicon_err(OE_PLUGIN, 0, "No such op: %s, expected merge or replace", opstr);
|
clicon_err(OE_PLUGIN, 0, "No such op: %s, expected merge or replace", opstr);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if ((cv = cvec_find_var(cvv, varstr)) == NULL){
|
if ((cv = cvec_find(cvv, varstr)) == NULL){
|
||||||
clicon_err(OE_PLUGIN, 0, "No such var name: %s", varstr);
|
clicon_err(OE_PLUGIN, 0, "No such var name: %s", varstr);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
@ -742,7 +763,7 @@ load_config_file(clicon_handle h,
|
||||||
}
|
}
|
||||||
/* Open and parse local file into xml */
|
/* Open and parse local file into xml */
|
||||||
if ((fd = open(filename, O_RDONLY)) < 0){
|
if ((fd = open(filename, O_RDONLY)) < 0){
|
||||||
clicon_err(OE_UNIX, errno, "%s: open(%s)", __FUNCTION__, filename);
|
clicon_err(OE_UNIX, errno, "open(%s)", filename);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (xml_parse_file(fd, "</clicon>", NULL, &xt) < 0)
|
if (xml_parse_file(fd, "</clicon>", NULL, &xt) < 0)
|
||||||
|
|
@ -772,10 +793,6 @@ load_config_file(clicon_handle h,
|
||||||
close(fd);
|
close(fd);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
int load_config_filev(clicon_handle h, cvec *vars, cvec *argv)
|
|
||||||
{
|
|
||||||
return load_config_file(h, vars, argv);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! Copy database to local file
|
/*! Copy database to local file
|
||||||
* Utility function used by cligen spec file
|
* Utility function used by cligen spec file
|
||||||
|
|
@ -808,9 +825,11 @@ save_config_file(clicon_handle h,
|
||||||
|
|
||||||
if (cvec_len(argv) != 2){
|
if (cvec_len(argv) != 2){
|
||||||
if (cvec_len(argv)==1)
|
if (cvec_len(argv)==1)
|
||||||
clicon_err(OE_PLUGIN, 0, "%s: Got single argument:\"%s\". Expected \"<dbname>,<varname>\"", cv_string_get(cvec_i(argv,0)));
|
clicon_err(OE_PLUGIN, 0, "Got single argument:\"%s\". Expected \"<dbname>,<varname>\"",
|
||||||
|
cv_string_get(cvec_i(argv,0)));
|
||||||
else
|
else
|
||||||
clicon_err(OE_PLUGIN, 0, "%s: Got %d arguments. Expected: <dbname>,<varname>", cvec_len(argv));
|
clicon_err(OE_PLUGIN, 0, " Got %d arguments. Expected: <dbname>,<varname>",
|
||||||
|
cvec_len(argv));
|
||||||
|
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
@ -822,7 +841,7 @@ save_config_file(clicon_handle h,
|
||||||
clicon_err(OE_PLUGIN, 0, "No such db name: %s", dbstr);
|
clicon_err(OE_PLUGIN, 0, "No such db name: %s", dbstr);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if ((cv = cvec_find_var(cvv, varstr)) == NULL){
|
if ((cv = cvec_find(cvv, varstr)) == NULL){
|
||||||
clicon_err(OE_PLUGIN, 0, "No such var name: %s", varstr);
|
clicon_err(OE_PLUGIN, 0, "No such var name: %s", varstr);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
@ -857,10 +876,6 @@ save_config_file(clicon_handle h,
|
||||||
fclose(f);
|
fclose(f);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
int save_config_filev(clicon_handle h, cvec *vars, cvec *argv)
|
|
||||||
{
|
|
||||||
return save_config_file(h, vars, argv);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! Delete all elements in a database
|
/*! Delete all elements in a database
|
||||||
* Utility function used by cligen spec file
|
* Utility function used by cligen spec file
|
||||||
|
|
@ -874,7 +889,7 @@ delete_all(clicon_handle h,
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
|
|
||||||
if (cvec_len(argv) != 1){
|
if (cvec_len(argv) != 1){
|
||||||
clicon_err(OE_PLUGIN, 0, "%s: Requires one element: dbname", __FUNCTION__);
|
clicon_err(OE_PLUGIN, 0, "Requires one element: dbname");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
dbstr = cv_string_get(cvec_i(argv, 0));
|
dbstr = cv_string_get(cvec_i(argv, 0));
|
||||||
|
|
@ -890,10 +905,6 @@ delete_all(clicon_handle h,
|
||||||
done:
|
done:
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
int delete_allv(clicon_handle h, cvec *vars, cvec *argv)
|
|
||||||
{
|
|
||||||
return delete_all(h, vars, argv);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! Discard all changes in candidate and replace with running
|
/*! Discard all changes in candidate and replace with running
|
||||||
*/
|
*/
|
||||||
|
|
@ -903,12 +914,8 @@ discard_changes(clicon_handle h,
|
||||||
cvec *argv)
|
cvec *argv)
|
||||||
{
|
{
|
||||||
return clicon_rpc_discard_changes(h);
|
return clicon_rpc_discard_changes(h);
|
||||||
}
|
|
||||||
int discard_changesv(clicon_handle h, cvec *vars, cvec *argv)
|
|
||||||
{
|
|
||||||
return discard_changes(h, vars, argv);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
}
|
||||||
/*! Copy from one database to another, eg running->startup
|
/*! Copy from one database to another, eg running->startup
|
||||||
* @param[in] argv a string: "<db1> <db2>" Copy from db1 to db2
|
* @param[in] argv a string: "<db1> <db2>" Copy from db1 to db2
|
||||||
*/
|
*/
|
||||||
|
|
@ -945,7 +952,7 @@ cli_notification_cb(int s,
|
||||||
if (clicon_msg_rcv(s, &reply, &eof) < 0)
|
if (clicon_msg_rcv(s, &reply, &eof) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (eof){
|
if (eof){
|
||||||
clicon_err(OE_PROTO, ESHUTDOWN, "%s: Socket unexpected close", __FUNCTION__);
|
clicon_err(OE_PROTO, ESHUTDOWN, "Socket unexpected close");
|
||||||
close(s);
|
close(s);
|
||||||
errno = ESHUTDOWN;
|
errno = ESHUTDOWN;
|
||||||
event_unreg_fd(s, cli_notification_cb);
|
event_unreg_fd(s, cli_notification_cb);
|
||||||
|
|
@ -992,7 +999,7 @@ cli_notification_cb(int s,
|
||||||
* and <format> is XXX
|
* and <format> is XXX
|
||||||
* Example code: Start logging of mystream and show logs as xml
|
* Example code: Start logging of mystream and show logs as xml
|
||||||
* @code
|
* @code
|
||||||
* cmd("comment"), cli_notifyv("mystream","1","xml");
|
* cmd("comment"), cli_notify("mystream","1","xml");
|
||||||
* @endcode
|
* @endcode
|
||||||
* XXX: format is a memory leak
|
* XXX: format is a memory leak
|
||||||
*/
|
*/
|
||||||
|
|
@ -1008,7 +1015,7 @@ cli_notify(clicon_handle h,
|
||||||
enum format_enum format = FORMAT_TEXT;
|
enum format_enum format = FORMAT_TEXT;
|
||||||
|
|
||||||
if (cvec_len(argv) != 2 && cvec_len(argv) != 3){
|
if (cvec_len(argv) != 2 && cvec_len(argv) != 3){
|
||||||
clicon_err(OE_PLUGIN, 0, "%s Requires arguments: <logstream> <status> [<format>]", __FUNCTION__);
|
clicon_err(OE_PLUGIN, 0, "Requires arguments: <logstream> <status> [<format>]");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
stream = cv_string_get(cvec_i(argv, 0));
|
stream = cv_string_get(cvec_i(argv, 0));
|
||||||
|
|
@ -1030,10 +1037,79 @@ cli_notify(clicon_handle h,
|
||||||
done:
|
done:
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Backward compatible Set if you want to enable "v" cli callback functions,
|
||||||
|
* such as cli_setv()
|
||||||
|
* This was obsoleted in 3.7.
|
||||||
|
* @see include/clixon_custom.h
|
||||||
|
*/
|
||||||
|
#ifdef COMPAT_CLIV
|
||||||
|
int cli_setv(clicon_handle h, cvec *vars, cvec *argv)
|
||||||
|
{
|
||||||
|
return cli_set(h, vars, argv);
|
||||||
|
}
|
||||||
|
int cli_mergev(clicon_handle h, cvec *vars, cvec *argv)
|
||||||
|
{
|
||||||
|
return cli_merge(h, vars, argv);
|
||||||
|
}
|
||||||
|
int cli_delv(clicon_handle h, cvec *vars, cvec *argv)
|
||||||
|
{
|
||||||
|
return cli_del(h, vars, argv);
|
||||||
|
}
|
||||||
|
int cli_debug_cliv(clicon_handle h, cvec *vars, cvec *argv)
|
||||||
|
{
|
||||||
|
return cli_debug_cli(h, vars, argv);
|
||||||
|
}
|
||||||
|
int cli_debug_backendv(clicon_handle h, cvec *vars, cvec *argv)
|
||||||
|
{
|
||||||
|
return cli_debug_backend(h, vars, argv);
|
||||||
|
}
|
||||||
|
int cli_set_modev(clicon_handle h, cvec *vars, cvec *argv)
|
||||||
|
{
|
||||||
|
return cli_set_mode(h, vars, argv);
|
||||||
|
}
|
||||||
|
int cli_start_shellv(clicon_handle h, cvec *vars, cvec *argv)
|
||||||
|
{
|
||||||
|
return cli_start_shell(h, vars, argv);
|
||||||
|
}
|
||||||
|
int cli_quitv(clicon_handle h, cvec *vars, cvec *argv)
|
||||||
|
{
|
||||||
|
return cli_quit(h, vars, argv);
|
||||||
|
}
|
||||||
|
int cli_commitv(clicon_handle h, cvec *vars, cvec *argv)
|
||||||
|
{
|
||||||
|
return cli_commit(h, vars, argv);
|
||||||
|
}
|
||||||
|
int cli_validatev(clicon_handle h, cvec *vars, cvec *argv)
|
||||||
|
{
|
||||||
|
return cli_validate(h, vars, argv);
|
||||||
|
|
||||||
|
}
|
||||||
|
int compare_dbsv(clicon_handle h, cvec *vars, cvec *argv)
|
||||||
|
{
|
||||||
|
return compare_dbs(h, vars, argv);
|
||||||
|
}
|
||||||
|
int load_config_filev(clicon_handle h, cvec *vars, cvec *argv)
|
||||||
|
{
|
||||||
|
return load_config_file(h, vars, argv);
|
||||||
|
}
|
||||||
|
int save_config_filev(clicon_handle h, cvec *vars, cvec *argv)
|
||||||
|
{
|
||||||
|
return save_config_file(h, vars, argv);
|
||||||
|
}
|
||||||
|
int delete_allv(clicon_handle h, cvec *vars, cvec *argv)
|
||||||
|
{
|
||||||
|
return delete_all(h, vars, argv);
|
||||||
|
}
|
||||||
|
int discard_changesv(clicon_handle h, cvec *vars, cvec *argv)
|
||||||
|
{
|
||||||
|
return discard_changes(h, vars, argv);
|
||||||
|
}
|
||||||
int cli_notifyv(clicon_handle h, cvec *vars, cvec *argv)
|
int cli_notifyv(clicon_handle h, cvec *vars, cvec *argv)
|
||||||
{
|
{
|
||||||
return cli_notify(h, vars, argv);
|
return cli_notify(h, vars, argv);
|
||||||
}
|
}
|
||||||
|
#endif /* COMPAT_CLIV */
|
||||||
|
|
||||||
/*! Lock database
|
/*! Lock database
|
||||||
*
|
*
|
||||||
|
|
@ -1113,7 +1189,7 @@ cli_unlock(clicon_handle h,
|
||||||
* tovar: Name of variable containing name of object to copy to.
|
* tovar: Name of variable containing name of object to copy to.
|
||||||
* @code
|
* @code
|
||||||
* cli spec:
|
* cli spec:
|
||||||
* copy snd <n1:string> to <n2:string>, cli_copy_config("candidate", "/sender[%s=%s]", "from", "n1", "n2");
|
* copy snd <n1:string> to <n2:string>, cli_copy_config("candidate", "/sender[%s='%s']", "from", "n1", "n2");
|
||||||
* cli command:
|
* cli command:
|
||||||
* copy snd from to to
|
* copy snd from to to
|
||||||
* @endcode
|
* @endcode
|
||||||
|
|
@ -1142,7 +1218,7 @@ cli_copy_config(clicon_handle h,
|
||||||
cxobj *xerr;
|
cxobj *xerr;
|
||||||
|
|
||||||
if (cvec_len(argv) != 5){
|
if (cvec_len(argv) != 5){
|
||||||
clicon_err(OE_PLUGIN, 0, "%s: Requires four elements: <db> <xpath> <keyname> <from> <to>", __FUNCTION__);
|
clicon_err(OE_PLUGIN, 0, "Requires four elements: <db> <xpath> <keyname> <from> <to>");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
/* First argv argument: Database */
|
/* First argv argument: Database */
|
||||||
|
|
@ -1157,7 +1233,7 @@ cli_copy_config(clicon_handle h,
|
||||||
tovar = cv_string_get(cvec_i(argv, 4));
|
tovar = cv_string_get(cvec_i(argv, 4));
|
||||||
|
|
||||||
/* Get from variable -> cv -> from name */
|
/* Get from variable -> cv -> from name */
|
||||||
if ((fromcv = cvec_find_var(cvv, fromvar)) == NULL){
|
if ((fromcv = cvec_find(cvv, fromvar)) == NULL){
|
||||||
clicon_err(OE_PLUGIN, 0, "fromvar '%s' not found in cligen var list", fromvar);
|
clicon_err(OE_PLUGIN, 0, "fromvar '%s' not found in cligen var list", fromvar);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
@ -1168,17 +1244,34 @@ cli_copy_config(clicon_handle h,
|
||||||
clicon_err(OE_PLUGIN, errno, "cbuf_new");
|
clicon_err(OE_PLUGIN, errno, "cbuf_new");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
/* Sanity check that xpath contains exactly one %s */
|
/* Sanity check that xpath contains exactly two %s, ie [%s='%s'] */
|
||||||
j = 0;
|
j = 0;
|
||||||
for (i=0; i<strlen(xpath); i++)
|
for (i=0; i<strlen(xpath); i++){
|
||||||
if (xpath[i] == '%')
|
if (xpath[i] == '%')
|
||||||
j++;
|
j++;
|
||||||
|
#ifdef COMPAT_XSL
|
||||||
|
/* This is a horrible kludge due to:
|
||||||
|
* (1) old xpath implementation wrongly did: a[b=x] instead of a[b='x']
|
||||||
|
* (2) cli_copy_config has as 2nd argument such an xpath provided by user.
|
||||||
|
*/
|
||||||
|
if (j==2){
|
||||||
|
int k;
|
||||||
|
if ((xpath[i-1] == '\'' || xpath[i-1] == '\"') &&
|
||||||
|
(xpath[i+2] == '\'' || xpath[i+2] == '\"')){
|
||||||
|
for (k=i-1;k<i+2;k++)
|
||||||
|
xpath[k] = xpath[k+1];
|
||||||
|
for (k=i+1;k<strlen(xpath)+1;k++)
|
||||||
|
xpath[k] = xpath[k+2];
|
||||||
|
i-=1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
if (j != 2){
|
if (j != 2){
|
||||||
clicon_err(OE_PLUGIN, 0, "xpath '%s' does not have two '%%'");
|
clicon_err(OE_PLUGIN, 0, "xpath '%s' does not have two '%%'", xpath);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
cprintf(cb, xpath, keyname, fromname);
|
cprintf(cb, xpath, keyname, fromname);
|
||||||
|
|
||||||
/* Get from object configuration and store in x1 */
|
/* Get from object configuration and store in x1 */
|
||||||
if (clicon_rpc_get_config(h, db, cbuf_get(cb), &x1) < 0)
|
if (clicon_rpc_get_config(h, db, cbuf_get(cb), &x1) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -1188,7 +1281,7 @@ cli_copy_config(clicon_handle h,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get to variable -> cv -> to name */
|
/* Get to variable -> cv -> to name */
|
||||||
if ((tocv = cvec_find_var(cvv, tovar)) == NULL){
|
if ((tocv = cvec_find(cvv, tovar)) == NULL){
|
||||||
clicon_err(OE_PLUGIN, 0, "tovar '%s' not found in cligen var list", tovar);
|
clicon_err(OE_PLUGIN, 0, "tovar '%s' not found in cligen var list", tovar);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
@ -1200,7 +1293,7 @@ cli_copy_config(clicon_handle h,
|
||||||
goto done;
|
goto done;
|
||||||
xml_name_set(x2, "config");
|
xml_name_set(x2, "config");
|
||||||
cprintf(cb, "/%s", keyname);
|
cprintf(cb, "/%s", keyname);
|
||||||
if ((x = xpath_first(x2, cbuf_get(cb))) == NULL){
|
if ((x = xpath_first(x2, "%s", cbuf_get(cb))) == NULL){
|
||||||
clicon_err(OE_PLUGIN, 0, "Field %s not found in copy tree", keyname);
|
clicon_err(OE_PLUGIN, 0, "Field %s not found in copy tree", keyname);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
@ -1237,7 +1330,7 @@ cli_debug(clicon_handle h,
|
||||||
cg_var *cv;
|
cg_var *cv;
|
||||||
int level;
|
int level;
|
||||||
|
|
||||||
if ((cv = cvec_find_var(vars, "level")) == NULL)
|
if ((cv = cvec_find(vars, "level")) == NULL)
|
||||||
cv = arg;
|
cv = arg;
|
||||||
level = cv_int32_get(cv);
|
level = cv_int32_get(cv);
|
||||||
/* cli */
|
/* cli */
|
||||||
|
|
|
||||||
|
|
@ -141,6 +141,7 @@ cli_expand_var_generate(clicon_handle h,
|
||||||
* @param[in] ys yang_stmt of the node at hand
|
* @param[in] ys yang_stmt of the node at hand
|
||||||
* @param[in] cb0 The string where the result format string is inserted.
|
* @param[in] cb0 The string where the result format string is inserted.
|
||||||
* @see cli_dbxml This is where the xmlkeyfmt string is used
|
* @see cli_dbxml This is where the xmlkeyfmt string is used
|
||||||
|
* @see pt_callback_reference in CLIgen where the actual callback overwrites the template
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
cli_callback_generate(clicon_handle h,
|
cli_callback_generate(clicon_handle h,
|
||||||
|
|
@ -204,20 +205,51 @@ yang2cli_var_sub(clicon_handle h,
|
||||||
}
|
}
|
||||||
type = ytype?ytype->ys_argument:NULL;
|
type = ytype?ytype->ys_argument:NULL;
|
||||||
cvtypestr = cv_type2str(cvtype);
|
cvtypestr = cv_type2str(cvtype);
|
||||||
|
if (type && strcmp(type, "identityref") == 0)
|
||||||
|
cprintf(cb, "(");
|
||||||
cprintf(cb, "<%s:%s", ys->ys_argument, cvtypestr);
|
cprintf(cb, "<%s:%s", ys->ys_argument, cvtypestr);
|
||||||
/* enumeration special case completion */
|
/* enumeration special case completion */
|
||||||
if (type && (strcmp(type, "enumeration") == 0 || strcmp(type, "bits") == 0)){
|
if (type){
|
||||||
cprintf(cb, " choice:");
|
if (strcmp(type, "enumeration") == 0 || strcmp(type, "bits") == 0){
|
||||||
i = 0;
|
cprintf(cb, " choice:");
|
||||||
while ((yi = yn_each((yang_node*)ytype, yi)) != NULL){
|
i = 0;
|
||||||
if (yi->ys_keyword != Y_ENUM && yi->ys_keyword != Y_BIT)
|
while ((yi = yn_each((yang_node*)ytype, yi)) != NULL){
|
||||||
continue;
|
if (yi->ys_keyword != Y_ENUM && yi->ys_keyword != Y_BIT)
|
||||||
if (i)
|
continue;
|
||||||
cprintf(cb, "|");
|
if (i)
|
||||||
cprintf(cb, "%s", yi->ys_argument);
|
cprintf(cb, "|");
|
||||||
i++;
|
cprintf(cb, "%s", yi->ys_argument);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (strcmp(type, "identityref") == 0){
|
||||||
|
yang_stmt *ybaseref;
|
||||||
|
yang_stmt *ybaseid;
|
||||||
|
cg_var *cv = NULL;
|
||||||
|
char *name;
|
||||||
|
char *id;
|
||||||
|
/* Add a wildchar string first -let validate take it for default prefix */
|
||||||
|
cprintf(cb, ">");
|
||||||
|
if (helptext)
|
||||||
|
cprintf(cb, "(\"%s\")", helptext);
|
||||||
|
cprintf(cb, "|<%s:%s choice:", ys->ys_argument, cvtypestr);
|
||||||
|
if ((ybaseref = yang_find((yang_node*)ytype, Y_BASE, NULL)) != NULL &&
|
||||||
|
(ybaseid = yang_find_identity(ys, ybaseref->ys_argument)) != NULL){
|
||||||
|
i = 0;
|
||||||
|
while ((cv = cvec_each(ybaseid->ys_cvec, cv)) != NULL){
|
||||||
|
if (i++)
|
||||||
|
cprintf(cb, "|");
|
||||||
|
name = strdup(cv_name_get(cv));
|
||||||
|
if ((id=strchr(name, ':')) != NULL)
|
||||||
|
*id = '\0';
|
||||||
|
cprintf(cb, "%s:%s", name, id+1);
|
||||||
|
if (name)
|
||||||
|
free(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options & YANG_OPTIONS_FRACTION_DIGITS)
|
if (options & YANG_OPTIONS_FRACTION_DIGITS)
|
||||||
cprintf(cb, " fraction-digits:%u", fraction_digits);
|
cprintf(cb, " fraction-digits:%u", fraction_digits);
|
||||||
if (options & (YANG_OPTIONS_RANGE|YANG_OPTIONS_LENGTH)){
|
if (options & (YANG_OPTIONS_RANGE|YANG_OPTIONS_LENGTH)){
|
||||||
|
|
@ -253,16 +285,18 @@ yang2cli_var_sub(clicon_handle h,
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cprintf(cb, "%s]", r);
|
cprintf(cb, "%s]", r); /* range */
|
||||||
free(r);
|
free(r);
|
||||||
r = NULL;
|
r = NULL;
|
||||||
}
|
}
|
||||||
if (options & YANG_OPTIONS_PATTERN)
|
if (options & YANG_OPTIONS_PATTERN)
|
||||||
cprintf(cb, " regexp:\"%s\"", pattern);
|
cprintf(cb, " regexp:\"%s\"", pattern);
|
||||||
|
|
||||||
cprintf(cb, ">");
|
cprintf(cb, ">");
|
||||||
if (helptext)
|
if (helptext)
|
||||||
cprintf(cb, "(\"%s\")", helptext);
|
cprintf(cb, "(\"%s\")", helptext);
|
||||||
|
if (type && strcmp(type, "identityref") == 0)
|
||||||
|
cprintf(cb, ")");
|
||||||
|
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
return retval;
|
return retval;
|
||||||
|
|
@ -385,6 +419,7 @@ yang2cli_var(clicon_handle h,
|
||||||
enum cv_type cvtype;
|
enum cv_type cvtype;
|
||||||
int options = 0;
|
int options = 0;
|
||||||
int completionp;
|
int completionp;
|
||||||
|
char *type;
|
||||||
|
|
||||||
if (yang_type_get(ys, &origtype, &yrestype,
|
if (yang_type_get(ys, &origtype, &yrestype,
|
||||||
&options, &mincv, &maxcv, &pattern, &fraction_digits) < 0)
|
&options, &mincv, &maxcv, &pattern, &fraction_digits) < 0)
|
||||||
|
|
@ -413,11 +448,11 @@ yang2cli_var(clicon_handle h,
|
||||||
cprintf(cb, ")");
|
cprintf(cb, ")");
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
char *type;
|
|
||||||
type = yrestype?yrestype->ys_argument:NULL;
|
type = yrestype?yrestype->ys_argument:NULL;
|
||||||
if (type)
|
if (type)
|
||||||
completionp = clicon_cli_genmodel_completion(h) &&
|
completionp = clicon_cli_genmodel_completion(h) &&
|
||||||
strcmp(type, "enumeration") != 0 &&
|
strcmp(type, "enumeration") != 0 &&
|
||||||
|
strcmp(type, "identityref") != 0 &&
|
||||||
strcmp(type, "bits") != 0;
|
strcmp(type, "bits") != 0;
|
||||||
else
|
else
|
||||||
completionp = clicon_cli_genmodel_completion(h);
|
completionp = clicon_cli_genmodel_completion(h);
|
||||||
|
|
@ -748,7 +783,7 @@ yang2cli(clicon_handle h,
|
||||||
cvec *globals; /* global variables from syntax */
|
cvec *globals; /* global variables from syntax */
|
||||||
|
|
||||||
if ((cbuf = cbuf_new()) == NULL){
|
if ((cbuf = cbuf_new()) == NULL){
|
||||||
clicon_err(OE_XML, errno, "%s: cbuf_new", __FUNCTION__);
|
clicon_err(OE_XML, errno, "cbuf_new");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
/* Traverse YANG specification: loop through statements */
|
/* Traverse YANG specification: loop through statements */
|
||||||
|
|
|
||||||
|
|
@ -71,7 +71,7 @@
|
||||||
#include "cli_handle.h"
|
#include "cli_handle.h"
|
||||||
|
|
||||||
/* Command line options to be passed to getopt(3) */
|
/* Command line options to be passed to getopt(3) */
|
||||||
#define CLI_OPTS "hD:f:xl:F:1u:d:m:qpGLy:c:"
|
#define CLI_OPTS "hD:f:xl:F:1u:d:m:qpGLy:c:U:"
|
||||||
|
|
||||||
/*! terminate cli application */
|
/*! terminate cli application */
|
||||||
static int
|
static int
|
||||||
|
|
@ -108,6 +108,8 @@ cli_signal_init (clicon_handle h)
|
||||||
|
|
||||||
/*! Interactive CLI command loop
|
/*! Interactive CLI command loop
|
||||||
* @param[in] h CLICON handle
|
* @param[in] h CLICON handle
|
||||||
|
* @retval 0
|
||||||
|
* @retval -1
|
||||||
* @see cligen_loop
|
* @see cligen_loop
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
|
|
@ -117,17 +119,16 @@ cli_interactive(clicon_handle h)
|
||||||
int res;
|
int res;
|
||||||
char *cmd;
|
char *cmd;
|
||||||
char *new_mode;
|
char *new_mode;
|
||||||
int result;
|
int eval;
|
||||||
|
|
||||||
/* Loop through all commands */
|
/* Loop through all commands */
|
||||||
while(!cligen_exiting(cli_cligen(h))) {
|
while(!cligen_exiting(cli_cligen(h))) {
|
||||||
new_mode = cli_syntax_mode(h);
|
new_mode = cli_syntax_mode(h);
|
||||||
if ((cmd = clicon_cliread(h)) == NULL) {
|
if ((cmd = clicon_cliread(h)) == NULL) {
|
||||||
cligen_exiting_set(cli_cligen(h), 1); /* EOF */
|
cligen_exiting_set(cli_cligen(h), 1); /* EOF */
|
||||||
retval = -1;
|
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if ((res = clicon_parse(h, cmd, &new_mode, &result)) < 0)
|
if ((res = clicon_parse(h, cmd, &new_mode, &eval)) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
retval = 0;
|
retval = 0;
|
||||||
|
|
@ -172,7 +173,7 @@ dump_configfile_xml_fn(FILE *fout,
|
||||||
clicon_err(OE_UNIX, errno, "configure file: %s", filename);
|
clicon_err(OE_UNIX, errno, "configure file: %s", filename);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
clicon_debug(2, "Reading config file %s", __FUNCTION__, filename);
|
clicon_debug(2, "%s: Reading config file %s", __FUNCTION__, filename);
|
||||||
fprintf(fout, "<config>\n");
|
fprintf(fout, "<config>\n");
|
||||||
while (fgets(line, sizeof(line), f)) {
|
while (fgets(line, sizeof(line), f)) {
|
||||||
if ((cp = strchr(line, '\n')) != NULL) /* strip last \n */
|
if ((cp = strchr(line, '\n')) != NULL) /* strip last \n */
|
||||||
|
|
@ -193,7 +194,8 @@ dump_configfile_xml_fn(FILE *fout,
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
usage(char *argv0, clicon_handle h)
|
usage(clicon_handle h,
|
||||||
|
char *argv0)
|
||||||
{
|
{
|
||||||
char *confsock = clicon_sock(h);
|
char *confsock = clicon_sock(h);
|
||||||
char *plgdir = clicon_cli_dir(h);
|
char *plgdir = clicon_cli_dir(h);
|
||||||
|
|
@ -216,7 +218,8 @@ usage(char *argv0, clicon_handle h)
|
||||||
"\t-L \t\tDebug print dynamic CLI syntax including completions and expansions\n"
|
"\t-L \t\tDebug print dynamic CLI syntax including completions and expansions\n"
|
||||||
"\t-l <s|e|o> \tLog on (s)yslog, std(e)rr or std(o)ut (stderr is default)\n"
|
"\t-l <s|e|o> \tLog on (s)yslog, std(e)rr or std(o)ut (stderr is default)\n"
|
||||||
"\t-y <file>\tOverride yang spec file (dont include .yang suffix)\n"
|
"\t-y <file>\tOverride yang spec file (dont include .yang suffix)\n"
|
||||||
"\t-c <file>\tSpecify cli spec file.\n",
|
"\t-c <file>\tSpecify cli spec file.\n"
|
||||||
|
"\t-U <user>\tOver-ride unix user with a pseudo user for NACM.\n",
|
||||||
argv0,
|
argv0,
|
||||||
confsock ? confsock : "none",
|
confsock ? confsock : "none",
|
||||||
plgdir ? plgdir : "none"
|
plgdir ? plgdir : "none"
|
||||||
|
|
@ -229,6 +232,7 @@ usage(char *argv0, clicon_handle h)
|
||||||
int
|
int
|
||||||
main(int argc, char **argv)
|
main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
|
int retval = -1;
|
||||||
char c;
|
char c;
|
||||||
int once;
|
int once;
|
||||||
char *tmp;
|
char *tmp;
|
||||||
|
|
@ -254,7 +258,9 @@ main(int argc, char **argv)
|
||||||
/* Initiate CLICON handle */
|
/* Initiate CLICON handle */
|
||||||
if ((h = cli_handle_init()) == NULL)
|
if ((h = cli_handle_init()) == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
/* Set username to clicon handle. Use in all communication to backend */
|
/* Set username to clicon handle. Use in all communication to backend
|
||||||
|
* Note, can be overridden by -U
|
||||||
|
*/
|
||||||
if ((pw = getpwuid(getuid())) == NULL){
|
if ((pw = getpwuid(getuid())) == NULL){
|
||||||
clicon_err(OE_UNIX, errno, "getpwuid");
|
clicon_err(OE_UNIX, errno, "getpwuid");
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -281,11 +287,11 @@ main(int argc, char **argv)
|
||||||
break;
|
break;
|
||||||
case 'D' : /* debug */
|
case 'D' : /* debug */
|
||||||
if (sscanf(optarg, "%d", &debug) != 1)
|
if (sscanf(optarg, "%d", &debug) != 1)
|
||||||
usage(argv[0], h);
|
usage(h, argv[0]);
|
||||||
break;
|
break;
|
||||||
case 'f': /* config file */
|
case 'f': /* config file */
|
||||||
if (!strlen(optarg))
|
if (!strlen(optarg))
|
||||||
usage(argv[0], h);
|
usage(h, argv[0]);
|
||||||
clicon_option_str_set(h, "CLICON_CONFIGFILE", optarg);
|
clicon_option_str_set(h, "CLICON_CONFIGFILE", optarg);
|
||||||
break;
|
break;
|
||||||
case 'x': /* dump config file as xml (migration from .conf file)*/
|
case 'x': /* dump config file as xml (migration from .conf file)*/
|
||||||
|
|
@ -303,9 +309,9 @@ main(int argc, char **argv)
|
||||||
logdst = CLICON_LOG_STDOUT;
|
logdst = CLICON_LOG_STDOUT;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
usage(argv[0], h);
|
usage(h, argv[0]);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
* Logs, error and debug to stderr or syslog, set debug level
|
* Logs, error and debug to stderr or syslog, set debug level
|
||||||
|
|
@ -325,7 +331,7 @@ main(int argc, char **argv)
|
||||||
/* Find and read configfile */
|
/* Find and read configfile */
|
||||||
if (clicon_options_main(h) < 0){
|
if (clicon_options_main(h) < 0){
|
||||||
if (help)
|
if (help)
|
||||||
usage(argv[0], h);
|
usage(h, argv[0]);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -350,17 +356,17 @@ main(int argc, char **argv)
|
||||||
break;
|
break;
|
||||||
case 'u': /* config unix domain path/ ip host */
|
case 'u': /* config unix domain path/ ip host */
|
||||||
if (!strlen(optarg))
|
if (!strlen(optarg))
|
||||||
usage(argv[0], h);
|
usage(h, argv[0]);
|
||||||
clicon_option_str_set(h, "CLICON_SOCK", optarg);
|
clicon_option_str_set(h, "CLICON_SOCK", optarg);
|
||||||
break;
|
break;
|
||||||
case 'd': /* Plugin directory: overrides configfile */
|
case 'd': /* Plugin directory: overrides configfile */
|
||||||
if (!strlen(optarg))
|
if (!strlen(optarg))
|
||||||
usage(argv[0], h);
|
usage(h, argv[0]);
|
||||||
clicon_option_str_set(h, "CLICON_CLI_DIR", optarg);
|
clicon_option_str_set(h, "CLICON_CLI_DIR", optarg);
|
||||||
break;
|
break;
|
||||||
case 'm': /* CLI syntax mode */
|
case 'm': /* CLI syntax mode */
|
||||||
if (!strlen(optarg))
|
if (!strlen(optarg))
|
||||||
usage(argv[0], h);
|
usage(h, argv[0]);
|
||||||
clicon_option_str_set(h, "CLICON_CLI_MODE", optarg);
|
clicon_option_str_set(h, "CLICON_CLI_MODE", optarg);
|
||||||
break;
|
break;
|
||||||
case 'q' : /* Quiet mode */
|
case 'q' : /* Quiet mode */
|
||||||
|
|
@ -383,8 +389,14 @@ main(int argc, char **argv)
|
||||||
clicon_option_str_set(h, "CLICON_CLISPEC_FILE", optarg);
|
clicon_option_str_set(h, "CLICON_CLISPEC_FILE", optarg);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case 'U': /* Clixon 'pseudo' user */
|
||||||
|
if (!strlen(optarg))
|
||||||
|
usage(h, argv[0]);
|
||||||
|
if (clicon_username_set(h, optarg) < 0)
|
||||||
|
goto done;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
usage(argv[0], h);
|
usage(h, argv[0]);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -393,7 +405,7 @@ main(int argc, char **argv)
|
||||||
|
|
||||||
/* Defer: Wait to the last minute to print help message */
|
/* Defer: Wait to the last minute to print help message */
|
||||||
if (help)
|
if (help)
|
||||||
usage(argv[0], h);
|
usage(h, argv[0]);
|
||||||
|
|
||||||
/* Setup signal handlers */
|
/* Setup signal handlers */
|
||||||
cli_signal_init(h);
|
cli_signal_init(h);
|
||||||
|
|
@ -445,7 +457,7 @@ main(int argc, char **argv)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!cli_syntax_mode(h)){
|
if (!cli_syntax_mode(h)){
|
||||||
fprintf (stderr, "FATAL: No cli mode set (use -m or CLICON_CLI_MODE)\n");
|
fprintf(stderr, "FATAL: No cli mode set (use -m or CLICON_CLI_MODE)\n");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (cligen_tree_find(cli_cligen(h), cli_syntax_mode(h)) == NULL)
|
if (cligen_tree_find(cli_cligen(h), cli_syntax_mode(h)) == NULL)
|
||||||
|
|
@ -476,11 +488,19 @@ main(int argc, char **argv)
|
||||||
if (restarg != NULL && strlen(restarg)){
|
if (restarg != NULL && strlen(restarg)){
|
||||||
char *mode = cli_syntax_mode(h);
|
char *mode = cli_syntax_mode(h);
|
||||||
int result;
|
int result;
|
||||||
clicon_parse(h, restarg, &mode, &result);
|
|
||||||
|
/* */
|
||||||
|
if (clicon_parse(h, restarg, &mode, &result) != 1){
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if (result < 0)
|
||||||
|
goto done;
|
||||||
}
|
}
|
||||||
/* Go into event-loop unless -1 command-line */
|
/* Go into event-loop unless -1 command-line */
|
||||||
if (!once)
|
if (!once)
|
||||||
cli_interactive(h);
|
retval = cli_interactive(h);
|
||||||
|
else
|
||||||
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
if (treename)
|
if (treename)
|
||||||
free(treename);
|
free(treename);
|
||||||
|
|
@ -491,6 +511,5 @@ main(int argc, char **argv)
|
||||||
clicon_log(LOG_NOTICE, "%s: %u Terminated\n", __PROGRAM__, getpid());
|
clicon_log(LOG_NOTICE, "%s: %u Terminated\n", __PROGRAM__, getpid());
|
||||||
if (h)
|
if (h)
|
||||||
cli_terminate(h);
|
cli_terminate(h);
|
||||||
|
return retval;
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -97,7 +97,7 @@ syntax_mode_find(cli_syntax_t *stx,
|
||||||
perror("malloc");
|
perror("malloc");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
memset (m, 0, sizeof (*m));
|
memset(m, 0, sizeof(*m));
|
||||||
strncpy(m->csm_name, mode, sizeof(m->csm_name)-1);
|
strncpy(m->csm_name, mode, sizeof(m->csm_name)-1);
|
||||||
strncpy(m->csm_prompt, CLI_DEFAULT_PROMPT, sizeof(m->csm_prompt)-1);
|
strncpy(m->csm_prompt, CLI_DEFAULT_PROMPT, sizeof(m->csm_prompt)-1);
|
||||||
INSQ(m, stx->stx_modes);
|
INSQ(m, stx->stx_modes);
|
||||||
|
|
@ -263,7 +263,7 @@ cli_load_syntax(clicon_handle h,
|
||||||
if ((cp = clixon_plugin_find(h, plgnam)) != NULL)
|
if ((cp = clixon_plugin_find(h, plgnam)) != NULL)
|
||||||
handle = cp->cp_handle;
|
handle = cp->cp_handle;
|
||||||
if (handle == NULL){
|
if (handle == NULL){
|
||||||
clicon_err(OE_PLUGIN, 0, "CLICON_PLUGIN set to '%s' in %s but plugin %s.so not found in %s\n",
|
clicon_err(OE_PLUGIN, 0, "CLICON_PLUGIN set to '%s' in %s but plugin %s.so not found in %s",
|
||||||
plgnam, filename, plgnam,
|
plgnam, filename, plgnam,
|
||||||
clicon_cli_dir(h));
|
clicon_cli_dir(h));
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -277,6 +277,9 @@ cli_load_syntax(clicon_handle h,
|
||||||
}
|
}
|
||||||
if (cligen_expandv_str2fn(pt, (expandv_str2fn_t*)clixon_str2fn, handle) < 0)
|
if (cligen_expandv_str2fn(pt, (expandv_str2fn_t*)clixon_str2fn, handle) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
/* Variable translation functions */
|
||||||
|
if (cligen_translate_str2fn(pt, (translate_str2fn_t*)clixon_str2fn, handle) < 0)
|
||||||
|
goto done;
|
||||||
|
|
||||||
/* Make sure we have a syntax mode specified */
|
/* Make sure we have a syntax mode specified */
|
||||||
if (mode == NULL || strlen(mode) < 1) { /* may be null if not given in file */
|
if (mode == NULL || strlen(mode) < 1) { /* may be null if not given in file */
|
||||||
|
|
@ -311,7 +314,7 @@ done:
|
||||||
* @param[in] h Clicon handle
|
* @param[in] h Clicon handle
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
cli_syntax_load (clicon_handle h)
|
cli_syntax_load(clicon_handle h)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
char *plugin_dir = NULL;
|
char *plugin_dir = NULL;
|
||||||
|
|
@ -340,7 +343,7 @@ cli_syntax_load (clicon_handle h)
|
||||||
clicon_err(OE_UNIX, errno, "malloc");
|
clicon_err(OE_UNIX, errno, "malloc");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
memset (stx, 0, sizeof (*stx)); /* Zero out all */
|
memset(stx, 0, sizeof(*stx)); /* Zero out all */
|
||||||
|
|
||||||
cli_syntax_set(h, stx);
|
cli_syntax_set(h, stx);
|
||||||
|
|
||||||
|
|
@ -441,6 +444,8 @@ cli_handler_err(FILE *f)
|
||||||
/*! Evaluate a matched command
|
/*! Evaluate a matched command
|
||||||
* @param[in] h Clicon handle
|
* @param[in] h Clicon handle
|
||||||
* @param[in] cmd The command string
|
* @param[in] cmd The command string
|
||||||
|
* @retval int If there is a callback, the return value of the callback is returned,
|
||||||
|
* @retval 0 otherwise
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
clicon_eval(clicon_handle h,
|
clicon_eval(clicon_handle h,
|
||||||
|
|
@ -448,10 +453,12 @@ clicon_eval(clicon_handle h,
|
||||||
cg_obj *match_obj,
|
cg_obj *match_obj,
|
||||||
cvec *cvv)
|
cvec *cvv)
|
||||||
{
|
{
|
||||||
|
int retval = 0;
|
||||||
|
|
||||||
cli_output_reset();
|
cli_output_reset();
|
||||||
if (!cligen_exiting(cli_cligen(h))) {
|
if (!cligen_exiting(cli_cligen(h))) {
|
||||||
clicon_err_reset();
|
clicon_err_reset();
|
||||||
if (cligen_eval(cli_cligen(h), match_obj, cvv) < 0) {
|
if ((retval = cligen_eval(cli_cligen(h), match_obj, cvv)) < 0) {
|
||||||
#if 0 /* This is removed since we get two error messages on failure.
|
#if 0 /* This is removed since we get two error messages on failure.
|
||||||
But maybe only sometime?
|
But maybe only sometime?
|
||||||
Both a real log when clicon_err is called, and the here again.
|
Both a real log when clicon_err is called, and the here again.
|
||||||
|
|
@ -460,11 +467,10 @@ clicon_eval(clicon_handle h,
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! Given a command string, parse and if match single command, eval it.
|
||||||
/*! Given a command string, parse and evaluate.
|
|
||||||
* Parse and evaluate the string according to
|
* Parse and evaluate the string according to
|
||||||
* the syntax parse tree of the syntax mode specified by *mode.
|
* the syntax parse tree of the syntax mode specified by *mode.
|
||||||
* If there is no match in the tree for the command, the parse hook
|
* If there is no match in the tree for the command, the parse hook
|
||||||
|
|
@ -475,19 +481,25 @@ clicon_eval(clicon_handle h,
|
||||||
* @param[in] h Clicon handle
|
* @param[in] h Clicon handle
|
||||||
* @param[in] cmd Command string
|
* @param[in] cmd Command string
|
||||||
* @param[in,out] modenamep Pointer to the mode string pointer
|
* @param[in,out] modenamep Pointer to the mode string pointer
|
||||||
* @param[out] result -2 On eof (shouldnt happen)
|
* @param[out] evalres Evaluation result if retval=1
|
||||||
|
* -2 On eof (shouldnt happen)
|
||||||
* -1 On parse error
|
* -1 On parse error
|
||||||
* >=0 Number of matches
|
* >=0 Number of matches
|
||||||
|
* @retval -2 Eof CG_EOF
|
||||||
|
* @retval -1 Error CG_ERROR
|
||||||
|
* @retval 0 No match CG_NOMATCH
|
||||||
|
* @retval 1 Exactly one match CG_MATCH
|
||||||
|
* @retval 2+ Multiple matches
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
clicon_parse(clicon_handle h,
|
clicon_parse(clicon_handle h,
|
||||||
char *cmd,
|
char *cmd,
|
||||||
char **modenamep,
|
char **modenamep,
|
||||||
int *result)
|
int *evalres)
|
||||||
{
|
{
|
||||||
|
int retval = -1;
|
||||||
char *modename;
|
char *modename;
|
||||||
char *modename0;
|
char *modename0;
|
||||||
int res = -1;
|
|
||||||
int r;
|
int r;
|
||||||
cli_syntax_t *stx = NULL;
|
cli_syntax_t *stx = NULL;
|
||||||
cli_syntaxmode_t *smode;
|
cli_syntaxmode_t *smode;
|
||||||
|
|
@ -508,10 +520,10 @@ clicon_parse(clicon_handle h,
|
||||||
else {
|
else {
|
||||||
if ((smode = syntax_mode_find(stx, modename, 0)) == NULL) {
|
if ((smode = syntax_mode_find(stx, modename, 0)) == NULL) {
|
||||||
cli_output(f, "Can't find syntax mode '%s'\n", modename);
|
cli_output(f, "Can't find syntax mode '%s'\n", modename);
|
||||||
return -1;
|
goto done;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while(smode) {
|
if (smode){
|
||||||
modename0 = NULL;
|
modename0 = NULL;
|
||||||
if ((pt = cligen_tree_active_get(cli_cligen(h))) != NULL)
|
if ((pt = cligen_tree_active_get(cli_cligen(h))) != NULL)
|
||||||
modename0 = pt->pt_name;
|
modename0 = pt->pt_name;
|
||||||
|
|
@ -527,20 +539,19 @@ clicon_parse(clicon_handle h,
|
||||||
clicon_err(OE_UNIX, errno, "cvec_new");
|
clicon_err(OE_UNIX, errno, "cvec_new");
|
||||||
goto done;;
|
goto done;;
|
||||||
}
|
}
|
||||||
res = cliread_parse(cli_cligen(h), cmd, pt, &match_obj, cvv);
|
retval = cliread_parse(cli_cligen(h), cmd, pt, &match_obj, cvv);
|
||||||
if (res != CG_MATCH)
|
if (retval != CG_MATCH)
|
||||||
pt_expand_cleanup_1(pt); /* XXX change to pt_expand_treeref_cleanup */
|
pt_expand_cleanup_1(pt); /* XXX change to pt_expand_treeref_cleanup */
|
||||||
if (modename0){
|
if (modename0){
|
||||||
cligen_tree_active_set(cli_cligen(h), modename0);
|
cligen_tree_active_set(cli_cligen(h), modename0);
|
||||||
modename0 = NULL;
|
modename0 = NULL;
|
||||||
}
|
}
|
||||||
switch (res) {
|
switch (retval) {
|
||||||
case CG_EOF: /* eof */
|
case CG_EOF: /* eof */
|
||||||
case CG_ERROR:
|
case CG_ERROR:
|
||||||
cli_output(f, "CLI parse error: %s\n", cmd);
|
cli_output(f, "CLI parse error: %s\n", cmd);
|
||||||
goto done;
|
break;
|
||||||
case CG_NOMATCH: /* no match */
|
case CG_NOMATCH: /* no match */
|
||||||
smode = NULL;
|
|
||||||
/* clicon_err(OE_CFG, 0, "CLI syntax error: \"%s\": %s",
|
/* clicon_err(OE_CFG, 0, "CLI syntax error: \"%s\": %s",
|
||||||
cmd, cli_nomatch(h));*/
|
cmd, cli_nomatch(h));*/
|
||||||
cli_output(f, "CLI syntax error: \"%s\": %s\n",
|
cli_output(f, "CLI syntax error: \"%s\": %s\n",
|
||||||
|
|
@ -554,20 +565,18 @@ clicon_parse(clicon_handle h,
|
||||||
if ((r = clicon_eval(h, cmd, match_obj, cvv)) < 0)
|
if ((r = clicon_eval(h, cmd, match_obj, cvv)) < 0)
|
||||||
cli_handler_err(stdout);
|
cli_handler_err(stdout);
|
||||||
pt_expand_cleanup_1(pt); /* XXX change to pt_expand_treeref_cleanup */
|
pt_expand_cleanup_1(pt); /* XXX change to pt_expand_treeref_cleanup */
|
||||||
if (result)
|
if (evalres)
|
||||||
*result = r;
|
*evalres = r;
|
||||||
goto done;
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
cli_output(f, "CLI syntax error: \"%s\" is ambiguous\n", cmd);
|
cli_output(f, "CLI syntax error: \"%s\" is ambiguous\n", cmd);
|
||||||
goto done;
|
|
||||||
break;
|
break;
|
||||||
}
|
} /* switch retval */
|
||||||
}
|
}
|
||||||
done:
|
done:
|
||||||
if (cvv)
|
if (cvv)
|
||||||
cvec_free(cvv);
|
cvec_free(cvv);
|
||||||
return res;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Read command from CLIgen's cliread() using current syntax mode.
|
/*! Read command from CLIgen's cliread() using current syntax mode.
|
||||||
|
|
@ -667,9 +676,9 @@ cli_set_prompt(clicon_handle h,
|
||||||
* @param[in] fmt Stdarg fmt string
|
* @param[in] fmt Stdarg fmt string
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
prompt_fmt (char *prompt,
|
prompt_fmt(char *prompt,
|
||||||
size_t plen,
|
size_t plen,
|
||||||
char *fmt, ...)
|
char *fmt, ...)
|
||||||
{
|
{
|
||||||
va_list ap;
|
va_list ap;
|
||||||
char *s = fmt;
|
char *s = fmt;
|
||||||
|
|
@ -689,7 +698,7 @@ prompt_fmt (char *prompt,
|
||||||
if (*s == '%' && *++s) {
|
if (*s == '%' && *++s) {
|
||||||
switch(*s) {
|
switch(*s) {
|
||||||
case 'H': /* Hostname */
|
case 'H': /* Hostname */
|
||||||
if (gethostname (hname, sizeof (hname)) != 0)
|
if (gethostname(hname, sizeof(hname)) != 0)
|
||||||
strncpy(hname, "unknown", sizeof(hname)-1);
|
strncpy(hname, "unknown", sizeof(hname)-1);
|
||||||
cprintf(cb, "%s", hname);
|
cprintf(cb, "%s", hname);
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -123,8 +123,7 @@ expand_dbvar(void *h,
|
||||||
char *reason = NULL;
|
char *reason = NULL;
|
||||||
|
|
||||||
if (argv == NULL || cvec_len(argv) != 2){
|
if (argv == NULL || cvec_len(argv) != 2){
|
||||||
clicon_err(OE_PLUGIN, 0, "%s: requires arguments: <db> <xmlkeyfmt>",
|
clicon_err(OE_PLUGIN, 0, "requires arguments: <db> <xmlkeyfmt>");
|
||||||
__FUNCTION__);
|
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if ((yspec = clicon_dbspec_yang(h)) == NULL){
|
if ((yspec = clicon_dbspec_yang(h)) == NULL){
|
||||||
|
|
@ -132,7 +131,7 @@ expand_dbvar(void *h,
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if ((cv = cvec_i(argv, 0)) == NULL){
|
if ((cv = cvec_i(argv, 0)) == NULL){
|
||||||
clicon_err(OE_PLUGIN, 0, "%s: Error when accessing argument <db>");
|
clicon_err(OE_PLUGIN, 0, "Error when accessing argument <db>");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
dbstr = cv_string_get(cv);
|
dbstr = cv_string_get(cv);
|
||||||
|
|
@ -143,13 +142,13 @@ expand_dbvar(void *h,
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if ((cv = cvec_i(argv, 1)) == NULL){
|
if ((cv = cvec_i(argv, 1)) == NULL){
|
||||||
clicon_err(OE_PLUGIN, 0, "%s: Error when accessing argument <api_path>");
|
clicon_err(OE_PLUGIN, 0, "Error when accessing argument <api_path>");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
api_path_fmt = cv_string_get(cv);
|
api_path_fmt = cv_string_get(cv);
|
||||||
/* api_path_fmt = /interface/%s/address/%s
|
/* api_path_fmt = /interface/%s/address/%s
|
||||||
--> ^/interface/eth0/address/.*$
|
--> ^/interface/eth0/address/.*$
|
||||||
--> /interface/[name=eth0]/address
|
--> /interface/[name="eth0"]/address
|
||||||
*/
|
*/
|
||||||
if (api_path_fmt2xpath(api_path_fmt, cvv, &xpath) < 0)
|
if (api_path_fmt2xpath(api_path_fmt, cvv, &xpath) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -161,7 +160,7 @@ expand_dbvar(void *h,
|
||||||
goto done;
|
goto done;
|
||||||
if ((xerr = xpath_first(xt, "/rpc-error")) != NULL){
|
if ((xerr = xpath_first(xt, "/rpc-error")) != NULL){
|
||||||
clicon_rpc_generate_error("Get configuration", xerr);
|
clicon_rpc_generate_error("Get configuration", xerr);
|
||||||
goto done;
|
goto ok;
|
||||||
}
|
}
|
||||||
xcur = xt; /* default top-of-tree */
|
xcur = xt; /* default top-of-tree */
|
||||||
xpathcur = xpath;
|
xpathcur = xpath;
|
||||||
|
|
@ -197,7 +196,7 @@ expand_dbvar(void *h,
|
||||||
cli_output(stderr, "%s\n", reason);
|
cli_output(stderr, "%s\n", reason);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if ((xcur = xpath_first(xt, xpath)) == NULL){
|
if ((xcur = xpath_first(xt, "%s", xpath)) == NULL){
|
||||||
clicon_err(OE_DB, 0, "xpath %s should return merged content", xpath);
|
clicon_err(OE_DB, 0, "xpath %s should return merged content", xpath);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
@ -205,7 +204,7 @@ expand_dbvar(void *h,
|
||||||
/* One round to detect duplicates
|
/* One round to detect duplicates
|
||||||
*/
|
*/
|
||||||
j = 0;
|
j = 0;
|
||||||
if (xpath_vec(xcur, xpathcur, &xvec, &xlen) < 0)
|
if (xpath_vec(xcur, "%s", &xvec, &xlen, xpathcur) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
for (i = 0; i < xlen; i++) {
|
for (i = 0; i < xlen; i++) {
|
||||||
char *str;
|
char *str;
|
||||||
|
|
@ -409,10 +408,6 @@ show_yang(clicon_handle h,
|
||||||
yang_print(stdout, yn);
|
yang_print(stdout, yn);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
int show_yangv(clicon_handle h, cvec *vars, cvec *argv)
|
|
||||||
{
|
|
||||||
return show_yang(h, vars, argv);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! Generic show configuration CLIGEN callback
|
/*! Generic show configuration CLIGEN callback
|
||||||
* Utility function used by cligen spec file
|
* Utility function used by cligen spec file
|
||||||
|
|
@ -421,11 +416,11 @@ int show_yangv(clicon_handle h, cvec *vars, cvec *argv)
|
||||||
* @param[in] argv String vector: <dbname> <format> <xpath> [<varname>]
|
* @param[in] argv String vector: <dbname> <format> <xpath> [<varname>]
|
||||||
* Format of argv:
|
* Format of argv:
|
||||||
* <dbname> "running"|"candidate"|"startup"
|
* <dbname> "running"|"candidate"|"startup"
|
||||||
* <dbname> "text"|"xml"|"json"|"cli"|"netconf" (see format_enum)
|
* <format> "text"|"xml"|"json"|"cli"|"netconf" (see format_enum)
|
||||||
* <xpath> xpath expression, that may contain one %, eg "/sender[name=%s]"
|
* <xpath> xpath expression, that may contain one %, eg "/sender[name="%s"]"
|
||||||
* <varname> optional name of variable in cvv. If set, xpath must have a '%s'
|
* <varname> optional name of variable in cvv. If set, xpath must have a '%s'
|
||||||
* @code
|
* @code
|
||||||
* show config id <n:string>, cli_show_config("running","xml","iface[name=%s]","n");
|
* show config id <n:string>, cli_show_config("running","xml","iface[name="%s"]","n");
|
||||||
* @endcode
|
* @endcode
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
|
|
@ -478,10 +473,11 @@ cli_show_config(clicon_handle h,
|
||||||
if (xpath[i] == '%')
|
if (xpath[i] == '%')
|
||||||
j++;
|
j++;
|
||||||
if (j != 1){
|
if (j != 1){
|
||||||
clicon_err(OE_PLUGIN, 0, "xpath '%s' does not have a single '%%'");
|
clicon_err(OE_PLUGIN, 0, "xpath '%s' does not have a single '%%'",
|
||||||
|
xpath);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if ((cvattr = cvec_find_var(cvv, attr)) == NULL){
|
if ((cvattr = cvec_find(cvv, attr)) == NULL){
|
||||||
clicon_err(OE_PLUGIN, 0, "attr '%s' not found in cligen var list", attr);
|
clicon_err(OE_PLUGIN, 0, "attr '%s' not found in cligen var list", attr);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
@ -565,7 +561,7 @@ show_conf_xpath(clicon_handle h,
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (cvec_len(argv) != 1){
|
if (cvec_len(argv) != 1){
|
||||||
clicon_err(OE_PLUGIN, 0, "%s: Requires one element to be <dbname>", __FUNCTION__);
|
clicon_err(OE_PLUGIN, 0, "Requires one element to be <dbname>");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
str = cv_string_get(cvec_i(argv, 0));
|
str = cv_string_get(cvec_i(argv, 0));
|
||||||
|
|
@ -576,7 +572,7 @@ show_conf_xpath(clicon_handle h,
|
||||||
clicon_err(OE_PLUGIN, 0, "No such db name: %s", str);
|
clicon_err(OE_PLUGIN, 0, "No such db name: %s", str);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
cv = cvec_find_var(cvv, "xpath");
|
cv = cvec_find(cvv, "xpath");
|
||||||
xpath = cv_string_get(cv);
|
xpath = cv_string_get(cv);
|
||||||
if (clicon_rpc_get_config(h, str, xpath, &xt) < 0)
|
if (clicon_rpc_get_config(h, str, xpath, &xt) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -584,7 +580,7 @@ show_conf_xpath(clicon_handle h,
|
||||||
clicon_rpc_generate_error("Get configuration", xerr);
|
clicon_rpc_generate_error("Get configuration", xerr);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (xpath_vec(xt, xpath, &xv, &xlen) < 0)
|
if (xpath_vec(xt, "%s", &xv, &xlen, xpath) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
for (i=0; i<xlen; i++)
|
for (i=0; i<xlen; i++)
|
||||||
xml_print(stdout, xv[i]);
|
xml_print(stdout, xv[i]);
|
||||||
|
|
@ -598,13 +594,105 @@ done:
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
int show_confv_xpath(clicon_handle h, cvec *vars, cvec *argv)
|
|
||||||
{
|
|
||||||
return show_conf_xpath(h, vars, argv);
|
|
||||||
}
|
|
||||||
|
|
||||||
int cli_show_version(clicon_handle h, cvec *vars, cvec *argv)
|
int cli_show_version(clicon_handle h, cvec *vars, cvec *argv)
|
||||||
{
|
{
|
||||||
cli_output(stdout, "%s\n", CLIXON_VERSION_STRING);
|
cli_output(stdout, "%s\n", CLIXON_VERSION_STRING);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! Generic show configuration CLIGEN callback using generated CLI syntax
|
||||||
|
* Format of argv:
|
||||||
|
* <api_path_fmt> Generated API PATH
|
||||||
|
* <dbname> "running"|"candidate"|"startup"
|
||||||
|
* <format> "text"|"xml"|"json"|"cli"|"netconf" (see format_enum)
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
cli_show_auto(clicon_handle h,
|
||||||
|
cvec *cvv,
|
||||||
|
cvec *argv)
|
||||||
|
{
|
||||||
|
int retval = 1;
|
||||||
|
yang_spec *yspec;
|
||||||
|
char *api_path_fmt; /* xml key format */
|
||||||
|
// char *api_path = NULL; /* xml key */
|
||||||
|
char *db;
|
||||||
|
char *xpath;
|
||||||
|
char *formatstr;
|
||||||
|
enum format_enum format = FORMAT_XML;
|
||||||
|
cxobj *xt = NULL;
|
||||||
|
cxobj *xp;
|
||||||
|
cxobj *xerr;
|
||||||
|
enum genmodel_type gt;
|
||||||
|
|
||||||
|
if (cvec_len(argv) != 3){
|
||||||
|
clicon_err(OE_PLUGIN, 0, "Usage: <api-path-fmt>* <database> <format>. (*) generated.");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
/* First argv argument: API_path format */
|
||||||
|
api_path_fmt = cv_string_get(cvec_i(argv, 0));
|
||||||
|
/* Second argv argument: Database */
|
||||||
|
db = cv_string_get(cvec_i(argv, 1));
|
||||||
|
/* Third format: output format */
|
||||||
|
formatstr = cv_string_get(cvec_i(argv, 2));
|
||||||
|
if ((format = format_str2int(formatstr)) < 0){
|
||||||
|
clicon_err(OE_PLUGIN, 0, "Not valid format: %s", formatstr);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if ((yspec = clicon_dbspec_yang(h)) == NULL){
|
||||||
|
clicon_err(OE_FATAL, 0, "No DB_SPEC");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if (api_path_fmt2api_path(api_path_fmt, cvv, &api_path) < 0)
|
||||||
|
// goto done;
|
||||||
|
if (api_path_fmt2xpath(api_path_fmt, cvv, &xpath) < 0)
|
||||||
|
goto done;
|
||||||
|
/* Get configuration from database */
|
||||||
|
if (clicon_rpc_get_config(h, db, xpath, &xt) < 0)
|
||||||
|
goto done;
|
||||||
|
if ((xerr = xpath_first(xt, "/rpc-error")) != NULL){
|
||||||
|
clicon_rpc_generate_error("Get configuration", xerr);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if ((xp = xpath_first(xt, "%s", xpath)) != NULL)
|
||||||
|
/* Print configuration according to format */
|
||||||
|
switch (format){
|
||||||
|
case FORMAT_XML:
|
||||||
|
clicon_xml2file(stdout, xp, 0, 1);
|
||||||
|
break;
|
||||||
|
case FORMAT_JSON:
|
||||||
|
xml2json(stdout, xp, 1);
|
||||||
|
break;
|
||||||
|
case FORMAT_TEXT:
|
||||||
|
xml2txt(stdout, xp, 0); /* tree-formed text */
|
||||||
|
break;
|
||||||
|
case FORMAT_CLI:
|
||||||
|
if ((gt = clicon_cli_genmodel_type(h)) == GT_ERR)
|
||||||
|
goto done;
|
||||||
|
xml2cli(stdout, xp, NULL, gt); /* cli syntax */
|
||||||
|
break;
|
||||||
|
case FORMAT_NETCONF:
|
||||||
|
fprintf(stdout, "<rpc><edit-config><target><candidate/></target><config>\n");
|
||||||
|
clicon_xml2file(stdout, xp, 2, 1);
|
||||||
|
fprintf(stdout, "</config></edit-config></rpc>]]>]]>\n");
|
||||||
|
break;
|
||||||
|
default: /* see cli_show_config() */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
retval = 0;
|
||||||
|
done:
|
||||||
|
if (xt)
|
||||||
|
xml_free(xt);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef COMPAT_CLIV
|
||||||
|
int show_yangv(clicon_handle h, cvec *vars, cvec *argv)
|
||||||
|
{
|
||||||
|
return show_yang(h, vars, argv);
|
||||||
|
}
|
||||||
|
int show_confv_xpath(clicon_handle h, cvec *vars, cvec *argv)
|
||||||
|
{
|
||||||
|
return show_conf_xpath(h, vars, argv);
|
||||||
|
}
|
||||||
|
#endif /* COMPAT_CLIV */
|
||||||
|
|
|
||||||
|
|
@ -72,55 +72,51 @@ int cli_notification_register(clicon_handle h, char *stream, enum format_enum fo
|
||||||
|
|
||||||
|
|
||||||
int cli_set(clicon_handle h, cvec *vars, cvec *argv);
|
int cli_set(clicon_handle h, cvec *vars, cvec *argv);
|
||||||
int cli_setv(clicon_handle h, cvec *vars, cvec *argv);
|
|
||||||
|
|
||||||
int cli_merge(clicon_handle h, cvec *vars, cvec *argv);
|
int cli_merge(clicon_handle h, cvec *vars, cvec *argv);
|
||||||
int cli_mergev(clicon_handle h, cvec *vars, cvec *argv);
|
|
||||||
|
|
||||||
int cli_create(clicon_handle h, cvec *vars, cvec *argv);
|
int cli_create(clicon_handle h, cvec *vars, cvec *argv);
|
||||||
int cli_remove(clicon_handle h, cvec *vars, cvec *argv);
|
int cli_remove(clicon_handle h, cvec *vars, cvec *argv);
|
||||||
|
|
||||||
int cli_del(clicon_handle h, cvec *vars, cvec *argv);
|
int cli_del(clicon_handle h, cvec *vars, cvec *argv);
|
||||||
int cli_delv(clicon_handle h, cvec *vars, cvec *argv);
|
|
||||||
|
|
||||||
int cli_debug_cli(clicon_handle h, cvec *vars, cvec *argv);
|
int cli_debug_cli(clicon_handle h, cvec *vars, cvec *argv);
|
||||||
int cli_debug_cliv(clicon_handle h, cvec *vars, cvec *argv);
|
|
||||||
|
|
||||||
int cli_debug_backend(clicon_handle h, cvec *vars, cvec *argv);
|
int cli_debug_backend(clicon_handle h, cvec *vars, cvec *argv);
|
||||||
int cli_debug_backendv(clicon_handle h, cvec *vars, cvec *argv);
|
|
||||||
|
|
||||||
|
int cli_debug_restconf(clicon_handle h, cvec *vars, cvec *argv);
|
||||||
|
|
||||||
int cli_set_mode(clicon_handle h, cvec *vars, cvec *argv);
|
int cli_set_mode(clicon_handle h, cvec *vars, cvec *argv);
|
||||||
int cli_set_modev(clicon_handle h, cvec *vars, cvec *argv);
|
|
||||||
|
|
||||||
int cli_start_shell(clicon_handle h, cvec *vars, cvec *argv);
|
int cli_start_shell(clicon_handle h, cvec *vars, cvec *argv);
|
||||||
int cli_start_shellv(clicon_handle h, cvec *vars, cvec *argv);
|
|
||||||
|
|
||||||
int cli_quit(clicon_handle h, cvec *vars, cvec *argv);
|
int cli_quit(clicon_handle h, cvec *vars, cvec *argv);
|
||||||
int cli_quitv(clicon_handle h, cvec *vars, cvec *argv);
|
|
||||||
|
|
||||||
int cli_commit(clicon_handle h, cvec *vars, cvec *argv);
|
int cli_commit(clicon_handle h, cvec *vars, cvec *argv);
|
||||||
int cli_commitv(clicon_handle h, cvec *vars, cvec *argv);
|
|
||||||
|
|
||||||
int cli_validate(clicon_handle h, cvec *vars, cvec *argv);
|
int cli_validate(clicon_handle h, cvec *vars, cvec *argv);
|
||||||
int cli_validatev(clicon_handle h, cvec *vars, cvec *argv);
|
|
||||||
|
|
||||||
int compare_dbs(clicon_handle h, cvec *vars, cvec *argv);
|
int compare_dbs(clicon_handle h, cvec *vars, cvec *argv);
|
||||||
int compare_dbsv(clicon_handle h, cvec *vars, cvec *argv);
|
|
||||||
|
|
||||||
int load_config_file(clicon_handle h, cvec *vars, cvec *argv);
|
int load_config_file(clicon_handle h, cvec *vars, cvec *argv);
|
||||||
int load_config_filev(clicon_handle h, cvec *vars, cvec *argv);
|
|
||||||
|
|
||||||
int save_config_file(clicon_handle h, cvec *vars, cvec *argv);
|
int save_config_file(clicon_handle h, cvec *vars, cvec *argv);
|
||||||
int save_config_filev(clicon_handle h, cvec *vars, cvec *argv);
|
|
||||||
|
|
||||||
int delete_all(clicon_handle h, cvec *vars, cvec *argv);
|
int delete_all(clicon_handle h, cvec *vars, cvec *argv);
|
||||||
int delete_allv(clicon_handle h, cvec *vars, cvec *argv);
|
|
||||||
|
|
||||||
int discard_changes(clicon_handle h, cvec *vars, cvec *argv);
|
int discard_changes(clicon_handle h, cvec *vars, cvec *argv);
|
||||||
int discard_changesv(clicon_handle h, cvec *vars, cvec *argv);
|
|
||||||
|
|
||||||
int cli_notify(clicon_handle h, cvec *cvv, cvec *argv);
|
int cli_notify(clicon_handle h, cvec *cvv, cvec *argv);
|
||||||
int cli_notifyv(clicon_handle h, cvec *cvv, cvec *argv);
|
|
||||||
|
|
||||||
int db_copy(clicon_handle h, cvec *cvv, cvec *argv);
|
int db_copy(clicon_handle h, cvec *cvv, cvec *argv);
|
||||||
|
|
||||||
|
|
@ -139,11 +135,34 @@ int expandv_dbvar(void *h, char *name, cvec *cvv, cvec *argv,
|
||||||
|
|
||||||
/* cli_show.c: CLIgen new vector arg callbacks */
|
/* cli_show.c: CLIgen new vector arg callbacks */
|
||||||
int show_yang(clicon_handle h, cvec *vars, cvec *argv);
|
int show_yang(clicon_handle h, cvec *vars, cvec *argv);
|
||||||
int show_yangv(clicon_handle h, cvec *vars, cvec *argv);
|
|
||||||
|
|
||||||
int show_conf_xpath(clicon_handle h, cvec *cvv, cvec *argv);
|
int show_conf_xpath(clicon_handle h, cvec *cvv, cvec *argv);
|
||||||
int show_confv_xpath(clicon_handle h, cvec *cvv, cvec *argv);
|
|
||||||
|
|
||||||
int cli_show_config(clicon_handle h, cvec *cvv, cvec *argv);
|
int cli_show_config(clicon_handle h, cvec *cvv, cvec *argv);
|
||||||
|
|
||||||
|
int cli_show_auto(clicon_handle h, cvec *cvv, cvec *argv);
|
||||||
|
|
||||||
|
#ifdef COMPAT_CLIV
|
||||||
|
int cli_setv(clicon_handle h, cvec *vars, cvec *argv);
|
||||||
|
int cli_mergev(clicon_handle h, cvec *vars, cvec *argv);
|
||||||
|
int cli_delv(clicon_handle h, cvec *vars, cvec *argv);
|
||||||
|
int cli_debug_cliv(clicon_handle h, cvec *vars, cvec *argv);
|
||||||
|
int cli_debug_backendv(clicon_handle h, cvec *vars, cvec *argv);
|
||||||
|
int cli_set_modev(clicon_handle h, cvec *vars, cvec *argv);
|
||||||
|
int cli_start_shellv(clicon_handle h, cvec *vars, cvec *argv);
|
||||||
|
int cli_quitv(clicon_handle h, cvec *vars, cvec *argv);
|
||||||
|
int cli_commitv(clicon_handle h, cvec *vars, cvec *argv);
|
||||||
|
int cli_validatev(clicon_handle h, cvec *vars, cvec *argv);
|
||||||
|
int compare_dbsv(clicon_handle h, cvec *vars, cvec *argv);
|
||||||
|
int load_config_filev(clicon_handle h, cvec *vars, cvec *argv);
|
||||||
|
int save_config_filev(clicon_handle h, cvec *vars, cvec *argv);
|
||||||
|
int delete_allv(clicon_handle h, cvec *vars, cvec *argv);
|
||||||
|
int discard_changesv(clicon_handle h, cvec *vars, cvec *argv);
|
||||||
|
int cli_notifyv(clicon_handle h, cvec *cvv, cvec *argv);
|
||||||
|
int show_yangv(clicon_handle h, cvec *vars, cvec *argv);
|
||||||
|
int show_confv_xpath(clicon_handle h, cvec *cvv, cvec *argv);
|
||||||
|
#endif /* COMPAT_CLIV */
|
||||||
|
|
||||||
#endif /* _CLIXON_CLI_API_H_ */
|
#endif /* _CLIXON_CLI_API_H_ */
|
||||||
|
|
|
||||||
|
|
@ -82,12 +82,15 @@
|
||||||
static int
|
static int
|
||||||
netconf_hello(cxobj *xn)
|
netconf_hello(cxobj *xn)
|
||||||
{
|
{
|
||||||
|
#ifdef nyi
|
||||||
cxobj *x;
|
cxobj *x;
|
||||||
|
|
||||||
x = NULL;
|
x = NULL;
|
||||||
|
|
||||||
while ((x = xpath_each(xn, "//capability", x)) != NULL) {
|
while ((x = xpath_each(xn, "//capability", x)) != NULL) {
|
||||||
//fprintf(stderr, "cap: %s\n", xml_body(x));
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -164,7 +164,7 @@ netconf_get_target(cxobj *xn,
|
||||||
cxobj *x;
|
cxobj *x;
|
||||||
char *target = NULL;
|
char *target = NULL;
|
||||||
|
|
||||||
if ((x = xpath_first(xn, path)) != NULL){
|
if ((x = xpath_first(xn, "%s", path)) != NULL){
|
||||||
if (xpath_first(x, "candidate") != NULL)
|
if (xpath_first(x, "candidate") != NULL)
|
||||||
target = "candidate";
|
target = "candidate";
|
||||||
else
|
else
|
||||||
|
|
|
||||||
|
|
@ -71,7 +71,7 @@
|
||||||
#include "netconf_rpc.h"
|
#include "netconf_rpc.h"
|
||||||
|
|
||||||
/* Command line options to be passed to getopt(3) */
|
/* Command line options to be passed to getopt(3) */
|
||||||
#define NETCONF_OPTS "hDqf:d:Sy:"
|
#define NETCONF_OPTS "hDqf:d:Sy:U:"
|
||||||
|
|
||||||
/*! Process incoming packet
|
/*! Process incoming packet
|
||||||
* @param[in] h Clicon handle
|
* @param[in] h Clicon handle
|
||||||
|
|
@ -134,6 +134,12 @@ process_incoming_packet(clicon_handle h,
|
||||||
if ((cbret = cbuf_new()) != NULL){
|
if ((cbret = cbuf_new()) != NULL){
|
||||||
if ((xc = xml_child_i(xret,0))!=NULL){
|
if ((xc = xml_child_i(xret,0))!=NULL){
|
||||||
xa=NULL;
|
xa=NULL;
|
||||||
|
/* Copy message-id attribute from incoming to reply.
|
||||||
|
* RFC 6241:
|
||||||
|
* If additional attributes are present in an <rpc> element, a NETCONF
|
||||||
|
* peer MUST return them unmodified in the <rpc-reply> element. This
|
||||||
|
* includes any "xmlns" attributes.
|
||||||
|
*/
|
||||||
while ((xa = xml_child_each(xrpc, xa, CX_ATTR)) != NULL){
|
while ((xa = xml_child_each(xrpc, xa, CX_ATTR)) != NULL){
|
||||||
if ((xa2 = xml_dup(xa)) ==NULL)
|
if ((xa2 = xml_dup(xa)) ==NULL)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -182,7 +188,7 @@ netconf_input_cb(int s,
|
||||||
int poll;
|
int poll;
|
||||||
|
|
||||||
if ((cb = cbuf_new()) == NULL){
|
if ((cb = cbuf_new()) == NULL){
|
||||||
clicon_err(OE_XML, errno, "%s: cbuf_new", __FUNCTION__);
|
clicon_err(OE_XML, errno, "cbuf_new");
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
memset(buf, 0, sizeof(buf));
|
memset(buf, 0, sizeof(buf));
|
||||||
|
|
@ -292,7 +298,8 @@ usage(clicon_handle h,
|
||||||
"\t-f <file>\tConfiguration file (mandatory)\n"
|
"\t-f <file>\tConfiguration file (mandatory)\n"
|
||||||
"\t-d <dir>\tSpecify netconf plugin directory dir (default: %s)\n"
|
"\t-d <dir>\tSpecify netconf plugin directory dir (default: %s)\n"
|
||||||
"\t-S\t\tLog on syslog\n"
|
"\t-S\t\tLog on syslog\n"
|
||||||
"\t-y <file>\tOverride yang spec file (dont include .yang suffix)\n",
|
"\t-y <file>\tOverride yang spec file (dont include .yang suffix)\n"
|
||||||
|
"\t-U <user>\tOver-ride unix user with a pseudo user for NACM.\n",
|
||||||
argv0,
|
argv0,
|
||||||
clicon_netconf_dir(h)
|
clicon_netconf_dir(h)
|
||||||
);
|
);
|
||||||
|
|
@ -379,6 +386,12 @@ main(int argc,
|
||||||
clicon_option_str_set(h, "CLICON_YANG_MODULE_MAIN", optarg);
|
clicon_option_str_set(h, "CLICON_YANG_MODULE_MAIN", optarg);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case 'U': /* Clixon 'pseudo' user */
|
||||||
|
if (!strlen(optarg))
|
||||||
|
usage(h, argv[0]);
|
||||||
|
if (clicon_username_set(h, optarg) < 0)
|
||||||
|
goto done;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
usage(h, argv[0]);
|
usage(h, argv[0]);
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -752,7 +752,7 @@ netconf_notification_cb(int s,
|
||||||
goto done;
|
goto done;
|
||||||
/* handle close from remote end: this will exit the client */
|
/* handle close from remote end: this will exit the client */
|
||||||
if (eof){
|
if (eof){
|
||||||
clicon_err(OE_PROTO, ESHUTDOWN, "%s: Socket unexpected close", __FUNCTION__);
|
clicon_err(OE_PROTO, ESHUTDOWN, "Socket unexpected close");
|
||||||
close(s);
|
close(s);
|
||||||
errno = ESHUTDOWN;
|
errno = ESHUTDOWN;
|
||||||
event_unreg_fd(s, netconf_notification_cb);
|
event_unreg_fd(s, netconf_notification_cb);
|
||||||
|
|
@ -770,13 +770,13 @@ netconf_notification_cb(int s,
|
||||||
/* find and apply filter */
|
/* find and apply filter */
|
||||||
if ((selector = xml_find_value(xfilter, "select")) == NULL)
|
if ((selector = xml_find_value(xfilter, "select")) == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
if (xpath_first(xe, selector) == NULL) {
|
if (xpath_first(xe, "%s", selector) == NULL) {
|
||||||
fprintf(stderr, "%s no match\n", __FUNCTION__); /* debug */
|
fprintf(stderr, "%s no match\n", __FUNCTION__); /* debug */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* create netconf message */
|
/* create netconf message */
|
||||||
if ((cb = cbuf_new()) == NULL){
|
if ((cb = cbuf_new()) == NULL){
|
||||||
clicon_err(OE_PLUGIN, errno, "%s: cbuf_new", __FUNCTION__);
|
clicon_err(OE_PLUGIN, errno, "cbuf_new");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
add_preamble(cb); /* Make it well-formed netconf xml */
|
add_preamble(cb); /* Make it well-formed netconf xml */
|
||||||
|
|
@ -888,12 +888,19 @@ netconf_application_rpc(clicon_handle h,
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
cbuf_reset(cb);
|
cbuf_reset(cb);
|
||||||
// if (xml_namespace(xn))
|
if (xml_namespace(xn) == NULL){
|
||||||
cprintf(cb, "/%s:%s", xml_namespace(xn), xml_name(xn));
|
xml_parse_va(xret, NULL, "<rpc-reply><rpc-error>"
|
||||||
// else
|
"<error-tag>operation-failed</error-tag>"
|
||||||
// cprintf(cb, "/%s", xml_name(xn)); /* XXX not accepdted by below */
|
"<error-type>rpc</error-type>"
|
||||||
|
"<error-severity>error</error-severity>"
|
||||||
|
"<error-message>%s</error-message>"
|
||||||
|
"<error-info>Not recognized</error-info>"
|
||||||
|
"</rpc-error></rpc-reply>", xml_name(xn));
|
||||||
|
goto ok;
|
||||||
|
}
|
||||||
|
cprintf(cb, "/%s:%s", xml_namespace(xn), xml_name(xn));
|
||||||
/* Find yang rpc statement, return yang rpc statement if found */
|
/* Find yang rpc statement, return yang rpc statement if found */
|
||||||
if (yang_abs_schema_nodeid(yspec, cbuf_get(cb), Y_RPC, &yrpc) < 0)
|
if (yang_abs_schema_nodeid(yspec, cbuf_get(cb), Y_RPC, &yrpc) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
/* Check if found */
|
/* Check if found */
|
||||||
if (yrpc != NULL){
|
if (yrpc != NULL){
|
||||||
|
|
@ -937,6 +944,7 @@ netconf_application_rpc(clicon_handle h,
|
||||||
retval = 1; /* handled by callback */
|
retval = 1; /* handled by callback */
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
ok:
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
if (cb)
|
if (cb)
|
||||||
|
|
@ -964,12 +972,26 @@ netconf_rpc_dispatch(clicon_handle h,
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
cxobj *xe;
|
cxobj *xe;
|
||||||
yang_spec *yspec = NULL;
|
yang_spec *yspec = NULL;
|
||||||
|
char *username;
|
||||||
|
cxobj *xa;
|
||||||
|
|
||||||
/* Check incoming RPC against system / netconf RPC:s */
|
/* Check incoming RPC against system / netconf RPC:s */
|
||||||
if ((yspec = clicon_netconf_yang(h)) == NULL){
|
if ((yspec = clicon_netconf_yang(h)) == NULL){
|
||||||
clicon_err(OE_YANG, ENOENT, "No netconf yang spec");
|
clicon_err(OE_YANG, ENOENT, "No netconf yang spec");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
/* Tag username on all incoming requests in case they are forwarded as internal messages
|
||||||
|
* This may be unecesary since not all are forwarded.
|
||||||
|
* It may even be wrong if something else is done with the incoming message?
|
||||||
|
*/
|
||||||
|
if ((username = clicon_username_get(h)) != NULL){
|
||||||
|
if ((xa = xml_new("username", xn, NULL)) == NULL)
|
||||||
|
goto done;
|
||||||
|
xml_type_set(xa, CX_ATTR);
|
||||||
|
if (xml_value_set(xa, username) < 0)
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
xe = NULL;
|
xe = NULL;
|
||||||
while ((xe = xml_child_each(xn, xe, CX_ELMNT)) != NULL) {
|
while ((xe = xml_child_each(xn, xe, CX_ELMNT)) != NULL) {
|
||||||
if (strcmp(xml_name(xe), "get-config") == 0){
|
if (strcmp(xml_name(xe), "get-config") == 0){
|
||||||
|
|
@ -1047,5 +1069,8 @@ netconf_rpc_dispatch(clicon_handle h,
|
||||||
}
|
}
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
|
/* Username attribute added at top - otherwise it is returned to sender */
|
||||||
|
if ((xa = xml_find(xn, "username")) != NULL)
|
||||||
|
xml_purge(xa);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,12 @@
|
||||||
|
|
||||||
### Installation using Nginx
|
### Installation using Nginx
|
||||||
|
|
||||||
Define nginx config file/etc/nginx/sites-available/default
|
Ensure www-data is member of the CLICON_SOCK_GROUP (default clicon). If not, add it:
|
||||||
|
```
|
||||||
|
sudo usermod -a -G clicon www-data
|
||||||
|
```
|
||||||
|
|
||||||
|
Define nginx config file: /etc/nginx/sites-available/default
|
||||||
```
|
```
|
||||||
server {
|
server {
|
||||||
...
|
...
|
||||||
|
|
@ -17,6 +22,11 @@ Start nginx daemon
|
||||||
```
|
```
|
||||||
sudo /etc/init.d nginx start
|
sudo /etc/init.d nginx start
|
||||||
```
|
```
|
||||||
|
Alternatively, start it via systemd:
|
||||||
|
```
|
||||||
|
sudo /etc/init.d/nginx start
|
||||||
|
sudo systemctl start start.service
|
||||||
|
```
|
||||||
|
|
||||||
Start clixon restconf daemon
|
Start clixon restconf daemon
|
||||||
```
|
```
|
||||||
|
|
|
||||||
|
|
@ -95,6 +95,9 @@ Mapping netconf error-tag -> status code
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "clixon_config.h" /* generated by config & autoconf */
|
||||||
|
#endif
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
@ -252,9 +255,9 @@ api_data_get2(clicon_handle h,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
if (xpath_vec(xret, path, &xvec, &xlen) < 0)
|
if (xpath_vec(xret, "%s", &xvec, &xlen, path) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
clicon_debug(1, "%s: xpath:%s xlen:%d", __FUNCTION__, path, xlen);
|
clicon_debug(1, "%s: xpath:%s xlen:%d", __FUNCTION__, path, (int)xlen);
|
||||||
if (use_xml){
|
if (use_xml){
|
||||||
for (i=0; i<xlen; i++){
|
for (i=0; i<xlen; i++){
|
||||||
x = xvec[i];
|
x = xvec[i];
|
||||||
|
|
@ -925,8 +928,7 @@ api_operations_get(clicon_handle h,
|
||||||
yang_spec *yspec;
|
yang_spec *yspec;
|
||||||
yang_stmt *ym;
|
yang_stmt *ym;
|
||||||
yang_stmt *yc;
|
yang_stmt *yc;
|
||||||
yang_stmt *yprefix;
|
char *modname;
|
||||||
char *prefix;
|
|
||||||
cbuf *cbx = NULL;
|
cbuf *cbx = NULL;
|
||||||
cxobj *xt = NULL;
|
cxobj *xt = NULL;
|
||||||
|
|
||||||
|
|
@ -937,15 +939,12 @@ api_operations_get(clicon_handle h,
|
||||||
cprintf(cbx, "<operations>");
|
cprintf(cbx, "<operations>");
|
||||||
ym = NULL;
|
ym = NULL;
|
||||||
while ((ym = yn_each((yang_node*)yspec, ym)) != NULL) {
|
while ((ym = yn_each((yang_node*)yspec, ym)) != NULL) {
|
||||||
if ((yprefix = yang_find((yang_node*)ym, Y_PREFIX, NULL)) != NULL)
|
modname = ym->ys_argument;
|
||||||
prefix = yprefix->ys_argument;
|
|
||||||
else
|
|
||||||
continue;
|
|
||||||
yc = NULL;
|
yc = NULL;
|
||||||
while ((yc = yn_each((yang_node*)ym, yc)) != NULL) {
|
while ((yc = yn_each((yang_node*)ym, yc)) != NULL) {
|
||||||
if (yc->ys_keyword != Y_RPC)
|
if (yc->ys_keyword != Y_RPC)
|
||||||
continue;
|
continue;
|
||||||
cprintf(cbx, "<%s:%s />", prefix, yc->ys_argument);
|
cprintf(cbx, "<%s:%s />", modname, yc->ys_argument);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cprintf(cbx, "</operations>");
|
cprintf(cbx, "</operations>");
|
||||||
|
|
@ -1030,6 +1029,9 @@ api_operations_post(clicon_handle h,
|
||||||
char *username;
|
char *username;
|
||||||
cbuf *cbret = NULL;
|
cbuf *cbret = NULL;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
char *prefix = NULL;
|
||||||
|
char *id = NULL;
|
||||||
|
yang_stmt *ys = NULL;
|
||||||
|
|
||||||
clicon_debug(1, "%s json:\"%s\" path:\"%s\"", __FUNCTION__, data, path);
|
clicon_debug(1, "%s json:\"%s\" path:\"%s\"", __FUNCTION__, data, path);
|
||||||
if ((yspec = clicon_dbspec_yang(h)) == NULL){
|
if ((yspec = clicon_dbspec_yang(h)) == NULL){
|
||||||
|
|
@ -1047,9 +1049,28 @@ api_operations_post(clicon_handle h,
|
||||||
}
|
}
|
||||||
clicon_debug(1, "%s oppath: %s", __FUNCTION__, oppath);
|
clicon_debug(1, "%s oppath: %s", __FUNCTION__, oppath);
|
||||||
|
|
||||||
/* Find yang rpc statement, return yang rpc statement if found */
|
/* Find yang rpc statement, return yang rpc statement if found
|
||||||
if (yang_abs_schema_nodeid(yspec, oppath, Y_RPC, &yrpc) < 0)
|
* POST {+restconf}/operations/<operation>
|
||||||
|
*
|
||||||
|
* The <operation> field identifies the module name and rpc identifier
|
||||||
|
* string for the desired operation.
|
||||||
|
*/
|
||||||
|
if (yang_nodeid_split(oppath+1, &prefix, &id) < 0) /* +1 skip / */
|
||||||
goto done;
|
goto done;
|
||||||
|
if ((ys = yang_find((yang_node*)yspec, Y_MODULE, prefix)) == NULL){
|
||||||
|
if (netconf_operation_failed_xml(&xerr, "protocol", "yang module not found") < 0)
|
||||||
|
goto done;
|
||||||
|
if (api_return_err(h, r, xerr, pretty, use_xml) < 0)
|
||||||
|
goto done;
|
||||||
|
goto ok;
|
||||||
|
}
|
||||||
|
if ((yrpc = yang_find((yang_node*)ys, Y_RPC, id)) == NULL){
|
||||||
|
if (netconf_operation_failed_xml(&xerr, "protocol", "yang node not found") < 0)
|
||||||
|
goto done;
|
||||||
|
if (api_return_err(h, r, xerr, pretty, use_xml) < 0)
|
||||||
|
goto done;
|
||||||
|
goto ok;
|
||||||
|
}
|
||||||
if (yrpc == NULL){
|
if (yrpc == NULL){
|
||||||
if (netconf_operation_failed_xml(&xerr, "protocol", "yang node not found") < 0)
|
if (netconf_operation_failed_xml(&xerr, "protocol", "yang node not found") < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -1224,6 +1245,10 @@ api_operations_post(clicon_handle h,
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
|
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
|
||||||
|
if (prefix)
|
||||||
|
free(prefix);
|
||||||
|
if (id)
|
||||||
|
free(id);
|
||||||
if (xdata)
|
if (xdata)
|
||||||
xml_free(xdata);
|
xml_free(xdata);
|
||||||
if (xtop)
|
if (xtop)
|
||||||
|
|
|
||||||
|
|
@ -1,46 +0,0 @@
|
||||||
#
|
|
||||||
# ***** BEGIN LICENSE BLOCK *****
|
|
||||||
#
|
|
||||||
# Copyright (C) 2009-2018 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 *****
|
|
||||||
#
|
|
||||||
|
|
||||||
#
|
|
||||||
# Include this file in your application Makefile using eg:
|
|
||||||
# -include $(datarootdir)/clixon/clixon.mk
|
|
||||||
# then you can use the DIRS below in your install rules.
|
|
||||||
# You also get rules for the application configure file.
|
|
||||||
# NOTE: APPNAME must be defined in the local Makefile
|
|
||||||
|
|
||||||
clixon_DBSPECDIR=prefix/share/$(APPNAME)
|
|
||||||
clixon_SYSCONFDIR=sysconfdir
|
|
||||||
clixon_LOCALSTATEDIR=localstatedir/$(APPNAME)
|
|
||||||
clixon_LIBDIR=libdir/$(APPNAME)
|
|
||||||
clixon_DATADIR=datadir/clixon # for system yang files
|
|
||||||
|
|
||||||
164
configure
vendored
164
configure
vendored
|
|
@ -621,6 +621,7 @@ ac_includes_default="\
|
||||||
|
|
||||||
ac_subst_vars='LTLIBOBJS
|
ac_subst_vars='LTLIBOBJS
|
||||||
LIBOBJS
|
LIBOBJS
|
||||||
|
CLIXON_DATADIR
|
||||||
EGREP
|
EGREP
|
||||||
GREP
|
GREP
|
||||||
LEXLIB
|
LEXLIB
|
||||||
|
|
@ -634,12 +635,12 @@ EXEEXT
|
||||||
ac_ct_CC
|
ac_ct_CC
|
||||||
with_restconf
|
with_restconf
|
||||||
RANLIB
|
RANLIB
|
||||||
AR
|
|
||||||
EXE_SUFFIX
|
|
||||||
SH_SUFFIX
|
SH_SUFFIX
|
||||||
AR_SUFFIX
|
|
||||||
OBJ_SUFFIX
|
|
||||||
INSTALLFLAGS
|
INSTALLFLAGS
|
||||||
|
INSTALL
|
||||||
|
INSTALL_DATA
|
||||||
|
INSTALL_SCRIPT
|
||||||
|
INSTALL_PROGRAM
|
||||||
CPPFLAGS
|
CPPFLAGS
|
||||||
INCLUDES
|
INCLUDES
|
||||||
LDFLAGS
|
LDFLAGS
|
||||||
|
|
@ -705,6 +706,7 @@ SHELL'
|
||||||
ac_subst_files=''
|
ac_subst_files=''
|
||||||
ac_user_opts='
|
ac_user_opts='
|
||||||
enable_option_checking
|
enable_option_checking
|
||||||
|
enable_debug
|
||||||
with_cligen
|
with_cligen
|
||||||
with_restconf
|
with_restconf
|
||||||
with_configfile
|
with_configfile
|
||||||
|
|
@ -1339,6 +1341,12 @@ if test -n "$ac_init_help"; then
|
||||||
|
|
||||||
cat <<\_ACEOF
|
cat <<\_ACEOF
|
||||||
|
|
||||||
|
Optional Features:
|
||||||
|
--disable-option-checking ignore unrecognized --enable/--with options
|
||||||
|
--disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no)
|
||||||
|
--enable-FEATURE[=ARG] include FEATURE [ARG=yes]
|
||||||
|
--enable-debug Build with debug symbols, default: no
|
||||||
|
|
||||||
Optional Packages:
|
Optional Packages:
|
||||||
--with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
|
--with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
|
||||||
--without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
|
--without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
|
||||||
|
|
@ -2147,10 +2155,11 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
|
||||||
: ${INSTALLFLAGS="-s"}
|
: ${INSTALLFLAGS="-s"}
|
||||||
|
|
||||||
CLIXON_VERSION_MAJOR="3"
|
CLIXON_VERSION_MAJOR="3"
|
||||||
CLIXON_VERSION_MINOR="6"
|
CLIXON_VERSION_MINOR="7"
|
||||||
CLIXON_VERSION_PATCH="1"
|
CLIXON_VERSION_PATCH="0"
|
||||||
CLIXON_VERSION="\"${CLIXON_VERSION_MAJOR}.${CLIXON_VERSION_MINOR}.${CLIXON_VERSION_PATCH}\""
|
CLIXON_VERSION="\"${CLIXON_VERSION_MAJOR}.${CLIXON_VERSION_MINOR}.${CLIXON_VERSION_PATCH}\""
|
||||||
# Fix to specific version (eg 3.5) or head (3)
|
|
||||||
|
# Fix to specific CLIgen version (eg 3.5) or head (3)
|
||||||
CLIGEN_VERSION="3"
|
CLIGEN_VERSION="3"
|
||||||
if test "$prefix" = "NONE"; then
|
if test "$prefix" = "NONE"; then
|
||||||
CLIGEN_PREFIX="$ac_default_prefix"
|
CLIGEN_PREFIX="$ac_default_prefix"
|
||||||
|
|
@ -2339,6 +2348,99 @@ test -n "$target_alias" &&
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Find a good install program. We prefer a C program (faster),
|
||||||
|
# so one script is as good as another. But avoid the broken or
|
||||||
|
# incompatible versions:
|
||||||
|
# SysV /etc/install, /usr/sbin/install
|
||||||
|
# SunOS /usr/etc/install
|
||||||
|
# IRIX /sbin/install
|
||||||
|
# AIX /bin/install
|
||||||
|
# AmigaOS /C/install, which installs bootblocks on floppy discs
|
||||||
|
# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
|
||||||
|
# AFS /usr/afsws/bin/install, which mishandles nonexistent args
|
||||||
|
# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
|
||||||
|
# OS/2's system install, which has a completely different semantic
|
||||||
|
# ./install, which can be erroneously created by make from ./install.sh.
|
||||||
|
# Reject install programs that cannot install multiple files.
|
||||||
|
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5
|
||||||
|
$as_echo_n "checking for a BSD-compatible install... " >&6; }
|
||||||
|
if test -z "$INSTALL"; then
|
||||||
|
if ${ac_cv_path_install+:} false; then :
|
||||||
|
$as_echo_n "(cached) " >&6
|
||||||
|
else
|
||||||
|
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
|
||||||
|
for as_dir in $PATH
|
||||||
|
do
|
||||||
|
IFS=$as_save_IFS
|
||||||
|
test -z "$as_dir" && as_dir=.
|
||||||
|
# Account for people who put trailing slashes in PATH elements.
|
||||||
|
case $as_dir/ in #((
|
||||||
|
./ | .// | /[cC]/* | \
|
||||||
|
/etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \
|
||||||
|
?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \
|
||||||
|
/usr/ucb/* ) ;;
|
||||||
|
*)
|
||||||
|
# OSF1 and SCO ODT 3.0 have their own names for install.
|
||||||
|
# Don't use installbsd from OSF since it installs stuff as root
|
||||||
|
# by default.
|
||||||
|
for ac_prog in ginstall scoinst install; do
|
||||||
|
for ac_exec_ext in '' $ac_executable_extensions; do
|
||||||
|
if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then
|
||||||
|
if test $ac_prog = install &&
|
||||||
|
grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
|
||||||
|
# AIX install. It has an incompatible calling convention.
|
||||||
|
:
|
||||||
|
elif test $ac_prog = install &&
|
||||||
|
grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
|
||||||
|
# program-specific install script used by HP pwplus--don't use.
|
||||||
|
:
|
||||||
|
else
|
||||||
|
rm -rf conftest.one conftest.two conftest.dir
|
||||||
|
echo one > conftest.one
|
||||||
|
echo two > conftest.two
|
||||||
|
mkdir conftest.dir
|
||||||
|
if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" &&
|
||||||
|
test -s conftest.one && test -s conftest.two &&
|
||||||
|
test -s conftest.dir/conftest.one &&
|
||||||
|
test -s conftest.dir/conftest.two
|
||||||
|
then
|
||||||
|
ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c"
|
||||||
|
break 3
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
done
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
done
|
||||||
|
IFS=$as_save_IFS
|
||||||
|
|
||||||
|
rm -rf conftest.one conftest.two conftest.dir
|
||||||
|
|
||||||
|
fi
|
||||||
|
if test "${ac_cv_path_install+set}" = set; then
|
||||||
|
INSTALL=$ac_cv_path_install
|
||||||
|
else
|
||||||
|
# As a last resort, use the slow shell script. Don't cache a
|
||||||
|
# value for INSTALL within a source directory, because that will
|
||||||
|
# break other packages using the cache if that directory is
|
||||||
|
# removed, or if the value is a relative name.
|
||||||
|
INSTALL=$ac_install_sh
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5
|
||||||
|
$as_echo "$INSTALL" >&6; }
|
||||||
|
|
||||||
|
# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
|
||||||
|
# It thinks the first close brace ends the variable substitution.
|
||||||
|
test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
|
||||||
|
|
||||||
|
test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}'
|
||||||
|
|
||||||
|
test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -3279,6 +3381,27 @@ CPPFLAGS="-DHAVE_CONFIG_H ${CPPFLAGS}"
|
||||||
|
|
||||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: compiler is $CC" >&5
|
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: compiler is $CC" >&5
|
||||||
$as_echo "compiler is $CC" >&6; }
|
$as_echo "compiler is $CC" >&6; }
|
||||||
|
# Debug flag
|
||||||
|
# Check whether --enable-debug was given.
|
||||||
|
if test "${enable_debug+set}" = set; then :
|
||||||
|
enableval=$enable_debug;
|
||||||
|
if test "$enableval" = no; then
|
||||||
|
ac_enable_debug=no
|
||||||
|
else
|
||||||
|
ac_enable_debug=yes
|
||||||
|
fi
|
||||||
|
|
||||||
|
else
|
||||||
|
ac_enable_debug=no
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: debug is $ac_enable_debug" >&5
|
||||||
|
$as_echo "debug is $ac_enable_debug" >&6; }
|
||||||
|
if test "$ac_enable_debug" = "yes"; then
|
||||||
|
CFLAGS="-g -Wall"
|
||||||
|
INSTALLFLAGS=""
|
||||||
|
fi
|
||||||
|
|
||||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: CPPFLAGS is $CPPFLAGS" >&5
|
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: CPPFLAGS is $CPPFLAGS" >&5
|
||||||
$as_echo "CPPFLAGS is $CPPFLAGS" >&6; }
|
$as_echo "CPPFLAGS is $CPPFLAGS" >&6; }
|
||||||
|
|
@ -3540,11 +3663,7 @@ _ACEOF
|
||||||
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
EXE_SUFFIX=""
|
|
||||||
OBJ_SUFFIX=".o"
|
|
||||||
AR_SUFFIX=".a"
|
|
||||||
SH_SUFFIX=".so"
|
SH_SUFFIX=".so"
|
||||||
AR="ar"
|
|
||||||
|
|
||||||
# This is for cligen
|
# This is for cligen
|
||||||
|
|
||||||
|
|
@ -4190,11 +4309,12 @@ fi
|
||||||
done
|
done
|
||||||
|
|
||||||
|
|
||||||
# This is to find clixon system files in the source code.
|
# This is to find clixon system files in the source code and Makefile
|
||||||
# same as clixon_DATADIR defined in clixon.mk.cpp for Makefiles
|
|
||||||
|
CLIXON_DATADIR="${prefix}/share/clixon"
|
||||||
|
|
||||||
cat >>confdefs.h <<_ACEOF
|
cat >>confdefs.h <<_ACEOF
|
||||||
#define CLIXON_DATADIR "${prefix}/share/clixon"
|
#define CLIXON_DATADIR "${CLIXON_DATADIR}"
|
||||||
_ACEOF
|
_ACEOF
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -4207,7 +4327,7 @@ _ACEOF
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
ac_config_files="$ac_config_files Makefile lib/Makefile lib/src/Makefile lib/clixon/Makefile apps/Makefile apps/cli/Makefile apps/backend/Makefile apps/netconf/Makefile apps/restconf/Makefile include/Makefile etc/Makefile etc/clixonrc example/Makefile example/docker/Makefile extras/rpm/Makefile docker/Makefile docker/cli/Makefile docker/cli/Dockerfile docker/backend/Makefile docker/backend/Dockerfile docker/netconf/Makefile docker/netconf/Dockerfile datastore/Makefile datastore/text/Makefile yang/Makefile doc/Makefile"
|
ac_config_files="$ac_config_files Makefile lib/Makefile lib/src/Makefile lib/clixon/Makefile apps/Makefile apps/cli/Makefile apps/backend/Makefile apps/netconf/Makefile apps/restconf/Makefile include/Makefile etc/Makefile etc/clixonrc example/Makefile extras/rpm/Makefile docker/Makefile datastore/Makefile datastore/text/Makefile util/Makefile yang/Makefile doc/Makefile"
|
||||||
|
|
||||||
cat >confcache <<\_ACEOF
|
cat >confcache <<\_ACEOF
|
||||||
# This file is a shell script that caches the results of configure
|
# This file is a shell script that caches the results of configure
|
||||||
|
|
@ -4787,6 +4907,7 @@ gives unlimited permission to copy, distribute and modify it."
|
||||||
|
|
||||||
ac_pwd='$ac_pwd'
|
ac_pwd='$ac_pwd'
|
||||||
srcdir='$srcdir'
|
srcdir='$srcdir'
|
||||||
|
INSTALL='$INSTALL'
|
||||||
test -n "\$AWK" || AWK=awk
|
test -n "\$AWK" || AWK=awk
|
||||||
_ACEOF
|
_ACEOF
|
||||||
|
|
||||||
|
|
@ -4913,17 +5034,11 @@ do
|
||||||
"etc/Makefile") CONFIG_FILES="$CONFIG_FILES etc/Makefile" ;;
|
"etc/Makefile") CONFIG_FILES="$CONFIG_FILES etc/Makefile" ;;
|
||||||
"etc/clixonrc") CONFIG_FILES="$CONFIG_FILES etc/clixonrc" ;;
|
"etc/clixonrc") CONFIG_FILES="$CONFIG_FILES etc/clixonrc" ;;
|
||||||
"example/Makefile") CONFIG_FILES="$CONFIG_FILES example/Makefile" ;;
|
"example/Makefile") CONFIG_FILES="$CONFIG_FILES example/Makefile" ;;
|
||||||
"example/docker/Makefile") CONFIG_FILES="$CONFIG_FILES example/docker/Makefile" ;;
|
|
||||||
"extras/rpm/Makefile") CONFIG_FILES="$CONFIG_FILES extras/rpm/Makefile" ;;
|
"extras/rpm/Makefile") CONFIG_FILES="$CONFIG_FILES extras/rpm/Makefile" ;;
|
||||||
"docker/Makefile") CONFIG_FILES="$CONFIG_FILES docker/Makefile" ;;
|
"docker/Makefile") CONFIG_FILES="$CONFIG_FILES docker/Makefile" ;;
|
||||||
"docker/cli/Makefile") CONFIG_FILES="$CONFIG_FILES docker/cli/Makefile" ;;
|
|
||||||
"docker/cli/Dockerfile") CONFIG_FILES="$CONFIG_FILES docker/cli/Dockerfile" ;;
|
|
||||||
"docker/backend/Makefile") CONFIG_FILES="$CONFIG_FILES docker/backend/Makefile" ;;
|
|
||||||
"docker/backend/Dockerfile") CONFIG_FILES="$CONFIG_FILES docker/backend/Dockerfile" ;;
|
|
||||||
"docker/netconf/Makefile") CONFIG_FILES="$CONFIG_FILES docker/netconf/Makefile" ;;
|
|
||||||
"docker/netconf/Dockerfile") CONFIG_FILES="$CONFIG_FILES docker/netconf/Dockerfile" ;;
|
|
||||||
"datastore/Makefile") CONFIG_FILES="$CONFIG_FILES datastore/Makefile" ;;
|
"datastore/Makefile") CONFIG_FILES="$CONFIG_FILES datastore/Makefile" ;;
|
||||||
"datastore/text/Makefile") CONFIG_FILES="$CONFIG_FILES datastore/text/Makefile" ;;
|
"datastore/text/Makefile") CONFIG_FILES="$CONFIG_FILES datastore/text/Makefile" ;;
|
||||||
|
"util/Makefile") CONFIG_FILES="$CONFIG_FILES util/Makefile" ;;
|
||||||
"yang/Makefile") CONFIG_FILES="$CONFIG_FILES yang/Makefile" ;;
|
"yang/Makefile") CONFIG_FILES="$CONFIG_FILES yang/Makefile" ;;
|
||||||
"doc/Makefile") CONFIG_FILES="$CONFIG_FILES doc/Makefile" ;;
|
"doc/Makefile") CONFIG_FILES="$CONFIG_FILES doc/Makefile" ;;
|
||||||
|
|
||||||
|
|
@ -5369,6 +5484,10 @@ ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
|
||||||
# CONFIG_FILE
|
# CONFIG_FILE
|
||||||
#
|
#
|
||||||
|
|
||||||
|
case $INSTALL in
|
||||||
|
[\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;;
|
||||||
|
*) ac_INSTALL=$ac_top_build_prefix$INSTALL ;;
|
||||||
|
esac
|
||||||
_ACEOF
|
_ACEOF
|
||||||
|
|
||||||
cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
|
cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
|
||||||
|
|
@ -5422,6 +5541,7 @@ s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t
|
||||||
s&@builddir@&$ac_builddir&;t t
|
s&@builddir@&$ac_builddir&;t t
|
||||||
s&@abs_builddir@&$ac_abs_builddir&;t t
|
s&@abs_builddir@&$ac_abs_builddir&;t t
|
||||||
s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
|
s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
|
||||||
|
s&@INSTALL@&$ac_INSTALL&;t t
|
||||||
$ac_datarootdir_hack
|
$ac_datarootdir_hack
|
||||||
"
|
"
|
||||||
eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \
|
eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \
|
||||||
|
|
|
||||||
50
configure.ac
50
configure.ac
|
|
@ -43,10 +43,11 @@ AC_INIT(lib/clixon/clixon.h.in)
|
||||||
: ${INSTALLFLAGS="-s"}
|
: ${INSTALLFLAGS="-s"}
|
||||||
|
|
||||||
CLIXON_VERSION_MAJOR="3"
|
CLIXON_VERSION_MAJOR="3"
|
||||||
CLIXON_VERSION_MINOR="6"
|
CLIXON_VERSION_MINOR="7"
|
||||||
CLIXON_VERSION_PATCH="1"
|
CLIXON_VERSION_PATCH="0"
|
||||||
CLIXON_VERSION="\"${CLIXON_VERSION_MAJOR}.${CLIXON_VERSION_MINOR}.${CLIXON_VERSION_PATCH}\""
|
CLIXON_VERSION="\"${CLIXON_VERSION_MAJOR}.${CLIXON_VERSION_MINOR}.${CLIXON_VERSION_PATCH}\""
|
||||||
# Fix to specific version (eg 3.5) or head (3)
|
|
||||||
|
# Fix to specific CLIgen version (eg 3.5) or head (3)
|
||||||
CLIGEN_VERSION="3"
|
CLIGEN_VERSION="3"
|
||||||
if test "$prefix" = "NONE"; then
|
if test "$prefix" = "NONE"; then
|
||||||
CLIGEN_PREFIX="$ac_default_prefix"
|
CLIGEN_PREFIX="$ac_default_prefix"
|
||||||
|
|
@ -73,18 +74,19 @@ AC_SUBST(CLIGEN_PREFIX)
|
||||||
AC_MSG_RESULT(CLIXON version is ${CLIXON_VERSION})
|
AC_MSG_RESULT(CLIXON version is ${CLIXON_VERSION})
|
||||||
|
|
||||||
AC_CANONICAL_TARGET
|
AC_CANONICAL_TARGET
|
||||||
|
|
||||||
AC_SUBST(CC)
|
AC_SUBST(CC)
|
||||||
AC_SUBST(CFLAGS)
|
AC_SUBST(CFLAGS)
|
||||||
AC_SUBST(LDFLAGS)
|
AC_SUBST(LDFLAGS)
|
||||||
AC_SUBST(INCLUDES)
|
AC_SUBST(INCLUDES)
|
||||||
AC_SUBST(CPPFLAGS)
|
AC_SUBST(CPPFLAGS)
|
||||||
|
AC_PROG_INSTALL
|
||||||
|
AC_SUBST(INSTALL)
|
||||||
|
AC_SUBST(INSTALL_DATA)
|
||||||
|
AC_SUBST(INSTALL_PROGRAM)
|
||||||
AC_SUBST(INSTALLFLAGS)
|
AC_SUBST(INSTALLFLAGS)
|
||||||
AC_SUBST(LIBS)
|
AC_SUBST(LIBS)
|
||||||
AC_SUBST(OBJ_SUFFIX)
|
|
||||||
AC_SUBST(AR_SUFFIX)
|
|
||||||
AC_SUBST(SH_SUFFIX)
|
AC_SUBST(SH_SUFFIX)
|
||||||
AC_SUBST(EXE_SUFFIX)
|
|
||||||
AC_SUBST(AR)
|
|
||||||
AC_SUBST(RANLIB)
|
AC_SUBST(RANLIB)
|
||||||
AC_SUBST(with_restconf) # If yes, compile apps/restconf
|
AC_SUBST(with_restconf) # If yes, compile apps/restconf
|
||||||
#
|
#
|
||||||
|
|
@ -94,6 +96,21 @@ AC_PROG_CPP
|
||||||
CPPFLAGS="-DHAVE_CONFIG_H ${CPPFLAGS}"
|
CPPFLAGS="-DHAVE_CONFIG_H ${CPPFLAGS}"
|
||||||
|
|
||||||
AC_MSG_RESULT(compiler is $CC)
|
AC_MSG_RESULT(compiler is $CC)
|
||||||
|
# Debug flag
|
||||||
|
AC_ARG_ENABLE(debug, AS_HELP_STRING([--enable-debug],[Build with debug symbols, default: no]),[
|
||||||
|
if test "$enableval" = no; then
|
||||||
|
ac_enable_debug=no
|
||||||
|
else
|
||||||
|
ac_enable_debug=yes
|
||||||
|
fi
|
||||||
|
],
|
||||||
|
[ ac_enable_debug=no])
|
||||||
|
|
||||||
|
AC_MSG_RESULT(debug is $ac_enable_debug)
|
||||||
|
if test "$ac_enable_debug" = "yes"; then
|
||||||
|
CFLAGS="-g -Wall"
|
||||||
|
INSTALLFLAGS=""
|
||||||
|
fi
|
||||||
|
|
||||||
AC_MSG_RESULT(CPPFLAGS is $CPPFLAGS)
|
AC_MSG_RESULT(CPPFLAGS is $CPPFLAGS)
|
||||||
AC_MSG_RESULT(CFLAGS is $CFLAGS)
|
AC_MSG_RESULT(CFLAGS is $CFLAGS)
|
||||||
|
|
@ -113,11 +130,7 @@ if test "$prefix" = "NONE"; then
|
||||||
fi
|
fi
|
||||||
|
|
||||||
AC_CHECK_LIB(m, main)
|
AC_CHECK_LIB(m, main)
|
||||||
EXE_SUFFIX=""
|
|
||||||
OBJ_SUFFIX=".o"
|
|
||||||
AR_SUFFIX=".a"
|
|
||||||
SH_SUFFIX=".so"
|
SH_SUFFIX=".so"
|
||||||
AR="ar"
|
|
||||||
|
|
||||||
# This is for cligen
|
# This is for cligen
|
||||||
AC_ARG_WITH(cligen, [ --with-cligen=dir Use CLIGEN here ] )
|
AC_ARG_WITH(cligen, [ --with-cligen=dir Use CLIGEN here ] )
|
||||||
|
|
@ -165,9 +178,10 @@ AC_CHECK_LIB(dl, dlopen)
|
||||||
|
|
||||||
AC_CHECK_FUNCS(inet_aton sigaction sigvec strlcpy strsep strndup alphasort versionsort strverscmp)
|
AC_CHECK_FUNCS(inet_aton sigaction sigvec strlcpy strsep strndup alphasort versionsort strverscmp)
|
||||||
|
|
||||||
# This is to find clixon system files in the source code.
|
# This is to find clixon system files in the source code and Makefile
|
||||||
# same as clixon_DATADIR defined in clixon.mk.cpp for Makefiles
|
AC_SUBST(CLIXON_DATADIR)
|
||||||
AC_DEFINE_UNQUOTED(CLIXON_DATADIR, "${prefix}/share/clixon", [Clixon data dir for system yang files etc])
|
CLIXON_DATADIR="${prefix}/share/clixon"
|
||||||
|
AC_DEFINE_UNQUOTED(CLIXON_DATADIR, "${CLIXON_DATADIR}", [Clixon data dir for system yang files etc])
|
||||||
|
|
||||||
# Default location for config file
|
# Default location for config file
|
||||||
AC_DEFINE_UNQUOTED(CLIXON_DEFAULT_CONFIG,"${DEFAULT_CONFIG}",[Location for apps to find default config file])
|
AC_DEFINE_UNQUOTED(CLIXON_DEFAULT_CONFIG,"${DEFAULT_CONFIG}",[Location for apps to find default config file])
|
||||||
|
|
@ -187,17 +201,11 @@ AC_OUTPUT(Makefile
|
||||||
etc/Makefile
|
etc/Makefile
|
||||||
etc/clixonrc
|
etc/clixonrc
|
||||||
example/Makefile
|
example/Makefile
|
||||||
example/docker/Makefile
|
|
||||||
extras/rpm/Makefile
|
extras/rpm/Makefile
|
||||||
docker/Makefile
|
docker/Makefile
|
||||||
docker/cli/Makefile
|
|
||||||
docker/cli/Dockerfile
|
|
||||||
docker/backend/Makefile
|
|
||||||
docker/backend/Dockerfile
|
|
||||||
docker/netconf/Makefile
|
|
||||||
docker/netconf/Dockerfile
|
|
||||||
datastore/Makefile
|
datastore/Makefile
|
||||||
datastore/text/Makefile
|
datastore/text/Makefile
|
||||||
|
util/Makefile
|
||||||
yang/Makefile
|
yang/Makefile
|
||||||
doc/Makefile
|
doc/Makefile
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -78,8 +78,6 @@ APPL = datastore_client
|
||||||
|
|
||||||
all: $(SUBDIRS) $(APPL)
|
all: $(SUBDIRS) $(APPL)
|
||||||
|
|
||||||
-include $(DESTDIR)$(datarootdir)/clixon/clixon.mk
|
|
||||||
|
|
||||||
.SUFFIXES:
|
.SUFFIXES:
|
||||||
.SUFFIXES: .c .o
|
.SUFFIXES: .c .o
|
||||||
|
|
||||||
|
|
@ -101,14 +99,11 @@ install-include:
|
||||||
for i in $(SUBDIRS); \
|
for i in $(SUBDIRS); \
|
||||||
do (cd $$i ; $(MAKE) $(MFLAGS) $@)||exit 1; done;
|
do (cd $$i ; $(MAKE) $(MFLAGS) $@)||exit 1; done;
|
||||||
|
|
||||||
install: $(APPL)
|
install:
|
||||||
install -d -m 0755 $(DESTDIR)$(bindir)
|
|
||||||
install -m 0755 $(INSTALLFLAGS) $(APPL) $(DESTDIR)$(bindir)
|
|
||||||
for i in $(SUBDIRS); \
|
for i in $(SUBDIRS); \
|
||||||
do (cd $$i && $(MAKE) $(MFLAGS) $@)||exit 1; done
|
do (cd $$i && $(MAKE) $(MFLAGS) $@)||exit 1; done
|
||||||
|
|
||||||
uninstall:
|
uninstall:
|
||||||
rm -f $(DESTDIR)$(bindir)/$(APPL)
|
|
||||||
for i in $(SUBDIRS); \
|
for i in $(SUBDIRS); \
|
||||||
do (cd $$i && $(MAKE) $(MFLAGS) $@)||exit 1; done
|
do (cd $$i && $(MAKE) $(MFLAGS) $@)||exit 1; done
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -63,7 +63,6 @@ OBJS = $(SRC:.c=.o)
|
||||||
|
|
||||||
all: $(PLUGIN)
|
all: $(PLUGIN)
|
||||||
|
|
||||||
-include $(DESTDIR)$(datarootdir)/clixon/clixon.mk
|
|
||||||
|
|
||||||
$(PLUGIN): $(SRC)
|
$(PLUGIN): $(SRC)
|
||||||
$(CC) $(CPPFLAGS) $(INCLUDES) $(CFLAGS) $(LDFLAGS) -shared -o $@ -lc $^ $(LIBS)
|
$(CC) $(CPPFLAGS) $(INCLUDES) $(CFLAGS) $(LDFLAGS) -shared -o $@ -lc $^ $(LIBS)
|
||||||
|
|
|
||||||
|
|
@ -92,7 +92,7 @@ chunk_initialize ()
|
||||||
|
|
||||||
chunk_pagesz = getpagesize();
|
chunk_pagesz = getpagesize();
|
||||||
|
|
||||||
bzero (&chunk_heads, sizeof (chunk_heads));
|
bzero (&chunk_heads, sizeof(chunk_heads));
|
||||||
|
|
||||||
for (idx = 0; idx < CHUNK_HEADS; idx++) {
|
for (idx = 0; idx < CHUNK_HEADS; idx++) {
|
||||||
chunk_head_t *chead = &chunk_heads[idx];
|
chunk_head_t *chead = &chunk_heads[idx];
|
||||||
|
|
@ -121,7 +121,7 @@ chunk_initialize ()
|
||||||
*/
|
*/
|
||||||
chead->ch_size =
|
chead->ch_size =
|
||||||
(chead->ch_blksz / chead->ch_nchkperblk)
|
(chead->ch_blksz / chead->ch_nchkperblk)
|
||||||
- sizeof (chunk_t);
|
- sizeof(chunk_t);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -150,22 +150,22 @@ chunk_new_block (chunk_head_t *chead)
|
||||||
PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
|
PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
|
||||||
if (blk == MAP_FAILED)
|
if (blk == MAP_FAILED)
|
||||||
return -1;
|
return -1;
|
||||||
memset ((void *)blk, 0, sizeof(*blk));
|
memset((void *)blk, 0, sizeof(*blk));
|
||||||
|
|
||||||
/* Allocate chunk block */
|
/* Allocate chunk block */
|
||||||
blk->cb_blk = (void *)
|
blk->cb_blk = (void *)
|
||||||
mmap(NULL, chead->ch_blksz,
|
mmap(NULL, chead->ch_blksz,
|
||||||
PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
|
PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
|
||||||
if (blk->cb_blk == MAP_FAILED) {
|
if (blk->cb_blk == MAP_FAILED) {
|
||||||
munmap (blk, chead->ch_blksz);
|
munmap(blk, chead->ch_blksz);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
memset (blk->cb_blk, 0, chead->ch_blksz);
|
memset(blk->cb_blk, 0, chead->ch_blksz);
|
||||||
|
|
||||||
|
|
||||||
/* Initialize chunk header */
|
/* Initialize chunk header */
|
||||||
blk->cb_head = chead;
|
blk->cb_head = chead;
|
||||||
INSQ (blk, chead->ch_blks);
|
INSQ(blk, chead->ch_blks);
|
||||||
chead->ch_nblks++;
|
chead->ch_nblks++;
|
||||||
|
|
||||||
/* Initialize chunks */
|
/* Initialize chunks */
|
||||||
|
|
@ -174,10 +174,10 @@ chunk_new_block (chunk_head_t *chead)
|
||||||
|
|
||||||
cnk = (chunk_t *)c;
|
cnk = (chunk_t *)c;
|
||||||
cnk->c_blk = blk;
|
cnk->c_blk = blk;
|
||||||
INSQ (cnk, chead->ch_free);
|
INSQ(cnk, chead->ch_free);
|
||||||
chead->ch_nfree++;
|
chead->ch_nfree++;
|
||||||
|
|
||||||
c += (chead->ch_size + sizeof (chunk_t));
|
c += (chead->ch_size + sizeof(chunk_t));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -188,7 +188,7 @@ chunk_new_block (chunk_head_t *chead)
|
||||||
* chunk_release_block() - Unqueue a block, it's chunks and free mem
|
* chunk_release_block() - Unqueue a block, it's chunks and free mem
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
chunk_release_block (chunk_block_t *cblk)
|
chunk_release_block(chunk_block_t *cblk)
|
||||||
{
|
{
|
||||||
int idx;
|
int idx;
|
||||||
char *c;
|
char *c;
|
||||||
|
|
@ -201,7 +201,7 @@ chunk_release_block (chunk_block_t *cblk)
|
||||||
/*
|
/*
|
||||||
* Dequeue block
|
* Dequeue block
|
||||||
*/
|
*/
|
||||||
DELQ (cblk, chead->ch_blks, chunk_block_t *);
|
DELQ(cblk, chead->ch_blks, chunk_block_t *);
|
||||||
chead->ch_nblks--;
|
chead->ch_nblks--;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -211,17 +211,17 @@ chunk_release_block (chunk_block_t *cblk)
|
||||||
for (idx = 0; idx < chead->ch_nchkperblk; idx++) {
|
for (idx = 0; idx < chead->ch_nchkperblk; idx++) {
|
||||||
|
|
||||||
cnk = (chunk_t *)c;
|
cnk = (chunk_t *)c;
|
||||||
DELQ (cnk, chead->ch_free, chunk_t *);
|
DELQ(cnk, chead->ch_free, chunk_t *);
|
||||||
chead->ch_nfree--;
|
chead->ch_nfree--;
|
||||||
|
|
||||||
c += (chead->ch_size + sizeof (chunk_t));
|
c += (chead->ch_size + sizeof(chunk_t));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Free block
|
* Free block
|
||||||
*/
|
*/
|
||||||
munmap ((void *)cblk->cb_blk, chead->ch_blksz);
|
munmap((void *)cblk->cb_blk, chead->ch_blksz);
|
||||||
munmap ((void *)cblk, sizeof(*cblk));
|
munmap((void *)cblk, sizeof(*cblk));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -230,7 +230,7 @@ chunk_release_block (chunk_block_t *cblk)
|
||||||
* chunk_alloc() - Map new chunk of memory
|
* chunk_alloc() - Map new chunk of memory
|
||||||
*/
|
*/
|
||||||
static void *
|
static void *
|
||||||
chunk_alloc (size_t len)
|
chunk_alloc(size_t len)
|
||||||
{
|
{
|
||||||
register int idx;
|
register int idx;
|
||||||
chunk_head_t *chead;
|
chunk_head_t *chead;
|
||||||
|
|
@ -258,21 +258,21 @@ chunk_alloc (size_t len)
|
||||||
|
|
||||||
/* Get new block if necessary */
|
/* Get new block if necessary */
|
||||||
if (!chead->ch_nfree)
|
if (!chead->ch_nfree)
|
||||||
if (chunk_new_block (chead))
|
if (chunk_new_block(chead))
|
||||||
return (void *)NULL;
|
return (void *)NULL;
|
||||||
|
|
||||||
|
|
||||||
/* Move a free chunk to the in-use list */
|
/* Move a free chunk to the in-use list */
|
||||||
cnk = chead->ch_free;
|
cnk = chead->ch_free;
|
||||||
DELQ (cnk, chead->ch_free, chunk_t *);
|
DELQ(cnk, chead->ch_free, chunk_t *);
|
||||||
chead->ch_nfree--;
|
chead->ch_nfree--;
|
||||||
INSQ (cnk, chead->ch_cnks);
|
INSQ(cnk, chead->ch_cnks);
|
||||||
/* Add reference to the corresponding block */
|
/* Add reference to the corresponding block */
|
||||||
cnk->c_blk->cb_ref++;
|
cnk->c_blk->cb_ref++;
|
||||||
|
|
||||||
#ifdef CHUNK_DIAG
|
#ifdef CHUNK_DIAG
|
||||||
/* Clear diag info */
|
/* Clear diag info */
|
||||||
bzero ((void *)&cnk->c_diag, sizeof (cnk->c_diag));
|
bzero((void *)&cnk->c_diag, sizeof(cnk->c_diag));
|
||||||
#endif /* CHUNK_DIAG */
|
#endif /* CHUNK_DIAG */
|
||||||
|
|
||||||
/* Return pointer to first byte after the chunk header */
|
/* Return pointer to first byte after the chunk header */
|
||||||
|
|
@ -285,9 +285,9 @@ chunk_alloc (size_t len)
|
||||||
*/
|
*/
|
||||||
void *
|
void *
|
||||||
#ifdef CHUNK_DIAG
|
#ifdef CHUNK_DIAG
|
||||||
_chunk (size_t len, const char *name, const char *file, int line)
|
_chunk(size_t len, const char *name, const char *file, int line)
|
||||||
#else
|
#else
|
||||||
chunk (size_t len, const char *name)
|
chunk(size_t len, const char *name)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
int newgrp = 0;
|
int newgrp = 0;
|
||||||
|
|
@ -306,10 +306,10 @@ chunk (size_t len, const char *name)
|
||||||
|
|
||||||
/* Get actual chunk
|
/* Get actual chunk
|
||||||
*/
|
*/
|
||||||
ptr = chunk_alloc (len);
|
ptr = chunk_alloc(len);
|
||||||
if (!ptr)
|
if (!ptr)
|
||||||
goto error;
|
goto error;
|
||||||
cnk = (chunk_t *) (((char *)ptr) - sizeof (chunk_t));
|
cnk = (chunk_t *) (((char *)ptr) - sizeof(chunk_t));
|
||||||
|
|
||||||
#ifdef CHUNK_DIAG
|
#ifdef CHUNK_DIAG
|
||||||
/* Store who reuested us
|
/* Store who reuested us
|
||||||
|
|
@ -329,7 +329,7 @@ chunk (size_t len, const char *name)
|
||||||
if (chunk_grp) {
|
if (chunk_grp) {
|
||||||
tmp = chunk_grp;
|
tmp = chunk_grp;
|
||||||
do {
|
do {
|
||||||
if (!strcmp (tmp->cg_name, name)) {
|
if (!strcmp(tmp->cg_name, name)) {
|
||||||
grp = tmp;
|
grp = tmp;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -343,26 +343,26 @@ chunk (size_t len, const char *name)
|
||||||
*/
|
*/
|
||||||
if ( !grp ) {
|
if ( !grp ) {
|
||||||
|
|
||||||
grp = (chunk_group_t *) chunk_alloc (sizeof (chunk_group_t));
|
grp = (chunk_group_t *) chunk_alloc(sizeof(chunk_group_t));
|
||||||
if (!grp)
|
if (!grp)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
bzero (grp, sizeof (chunk_group_t));
|
bzero(grp, sizeof(chunk_group_t));
|
||||||
|
|
||||||
grp->cg_name = (char *) chunk_alloc (strlen (name) + 1);
|
grp->cg_name = (char *) chunk_alloc(strlen(name) + 1);
|
||||||
if (!grp->cg_name)
|
if (!grp->cg_name)
|
||||||
goto error;
|
goto error;
|
||||||
bcopy (name, grp->cg_name, strlen(name)+1);
|
bcopy(name, grp->cg_name, strlen(name)+1);
|
||||||
newgrp = 1;
|
newgrp = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Get new entry.
|
/* Get new entry.
|
||||||
*/
|
*/
|
||||||
ent = (chunk_grpent_t *) chunk_alloc (sizeof (chunk_grpent_t));
|
ent = (chunk_grpent_t *) chunk_alloc(sizeof(chunk_grpent_t));
|
||||||
if (!ent)
|
if (!ent)
|
||||||
goto error;
|
goto error;
|
||||||
bzero (ent, sizeof (chunk_grpent_t));
|
bzero(ent, sizeof(chunk_grpent_t));
|
||||||
|
|
||||||
/* Now put everything together
|
/* Now put everything together
|
||||||
*/
|
*/
|
||||||
|
|
@ -371,22 +371,22 @@ chunk (size_t len, const char *name)
|
||||||
ent->ce_cnk = cnk;
|
ent->ce_cnk = cnk;
|
||||||
ent->ce_grp = grp;
|
ent->ce_grp = grp;
|
||||||
|
|
||||||
INSQ (ent, grp->cg_ent);
|
INSQ(ent, grp->cg_ent);
|
||||||
if (newgrp)
|
if (newgrp)
|
||||||
INSQ (grp, chunk_grp);
|
INSQ(grp, chunk_grp);
|
||||||
|
|
||||||
return (ptr);
|
return (ptr);
|
||||||
|
|
||||||
error:
|
error:
|
||||||
if (grp && newgrp) {
|
if (grp && newgrp) {
|
||||||
if (grp->cg_name)
|
if (grp->cg_name)
|
||||||
unchunk (grp->cg_name);
|
unchunk(grp->cg_name);
|
||||||
unchunk (grp);
|
unchunk(grp);
|
||||||
}
|
}
|
||||||
if (ent)
|
if (ent)
|
||||||
unchunk (ent);
|
unchunk(ent);
|
||||||
if (ptr)
|
if (ptr)
|
||||||
unchunk (ptr);
|
unchunk(ptr);
|
||||||
|
|
||||||
return (void *) NULL;
|
return (void *) NULL;
|
||||||
}
|
}
|
||||||
|
|
@ -397,9 +397,9 @@ chunk (size_t len, const char *name)
|
||||||
*/
|
*/
|
||||||
void *
|
void *
|
||||||
#ifdef CHUNK_DIAG
|
#ifdef CHUNK_DIAG
|
||||||
_rechunk (void *ptr, size_t len, const char *name, const char *file, int line)
|
_rechunk(void *ptr, size_t len, const char *name, const char *file, int line)
|
||||||
#else
|
#else
|
||||||
rechunk (void *ptr, size_t len, const char *name)
|
rechunk(void *ptr, size_t len, const char *name)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
int idx;
|
int idx;
|
||||||
|
|
@ -414,22 +414,22 @@ rechunk (void *ptr, size_t len, const char *name)
|
||||||
*/
|
*/
|
||||||
if (!ptr) {
|
if (!ptr) {
|
||||||
#ifdef CHUNK_DIAG
|
#ifdef CHUNK_DIAG
|
||||||
return _chunk (len, name, file, line);
|
return _chunk(len, name, file, line);
|
||||||
#else
|
#else
|
||||||
return chunk (len, name);
|
return chunk(len, name);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Zero length, free chunk
|
/* Zero length, free chunk
|
||||||
*/
|
*/
|
||||||
if (len == 0) {
|
if (len == 0) {
|
||||||
unchunk (ptr);
|
unchunk(ptr);
|
||||||
return (void *) NULL;
|
return (void *) NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Rewind pointer to beginning of chunk header
|
/* Rewind pointer to beginning of chunk header
|
||||||
*/
|
*/
|
||||||
cnk = (chunk_t *) (((char *)ptr) - sizeof (chunk_t));
|
cnk = (chunk_t *) (((char *)ptr) - sizeof(chunk_t));
|
||||||
chead = cnk->c_blk->cb_head;
|
chead = cnk->c_blk->cb_head;
|
||||||
|
|
||||||
/* Find sufficient sized block head
|
/* Find sufficient sized block head
|
||||||
|
|
@ -451,22 +451,22 @@ rechunk (void *ptr, size_t len, const char *name)
|
||||||
/* Get new chunk
|
/* Get new chunk
|
||||||
*/
|
*/
|
||||||
#ifdef CHUNK_DIAG
|
#ifdef CHUNK_DIAG
|
||||||
new = _chunk (len, name, file, line);
|
new = _chunk(len, name, file, line);
|
||||||
#else
|
#else
|
||||||
new = chunk (len, name);
|
new = chunk(len, name);
|
||||||
#endif
|
#endif
|
||||||
if (!new)
|
if (!new)
|
||||||
return (void *) NULL;
|
return (void *) NULL;
|
||||||
newcnk = (chunk_t *) (((char *)new) - sizeof (chunk_t));
|
newcnk = (chunk_t *) (((char *)new) - sizeof(chunk_t));
|
||||||
newchead = newcnk->c_blk->cb_head;
|
newchead = newcnk->c_blk->cb_head;
|
||||||
|
|
||||||
/* Copy contents to new chunk
|
/* Copy contents to new chunk
|
||||||
*/
|
*/
|
||||||
bcopy (ptr, new, MIN(newchead->ch_size, chead->ch_size));
|
bcopy(ptr, new, MIN(newchead->ch_size, chead->ch_size));
|
||||||
|
|
||||||
/* Free old chunk
|
/* Free old chunk
|
||||||
*/
|
*/
|
||||||
unchunk (ptr);
|
unchunk(ptr);
|
||||||
|
|
||||||
|
|
||||||
return (new);
|
return (new);
|
||||||
|
|
@ -476,7 +476,7 @@ rechunk (void *ptr, size_t len, const char *name)
|
||||||
* unchunk() - Release chunk
|
* unchunk() - Release chunk
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
unchunk (void *ptr)
|
unchunk(void *ptr)
|
||||||
{
|
{
|
||||||
chunk_t *cnk;
|
chunk_t *cnk;
|
||||||
chunk_head_t *chead;
|
chunk_head_t *chead;
|
||||||
|
|
@ -489,14 +489,14 @@ unchunk (void *ptr)
|
||||||
|
|
||||||
/* Rewind pointer to beginning of chunk header
|
/* Rewind pointer to beginning of chunk header
|
||||||
*/
|
*/
|
||||||
cnk = (chunk_t *) (((char *)ptr) - sizeof (chunk_t));
|
cnk = (chunk_t *) (((char *)ptr) - sizeof(chunk_t));
|
||||||
cblk = cnk->c_blk;
|
cblk = cnk->c_blk;
|
||||||
chead = cblk->cb_head;
|
chead = cblk->cb_head;
|
||||||
|
|
||||||
/* Move chunk back to free list
|
/* Move chunk back to free list
|
||||||
*/
|
*/
|
||||||
DELQ (cnk, chead->ch_cnks, chunk_t *);
|
DELQ(cnk, chead->ch_cnks, chunk_t *);
|
||||||
INSQ (cnk, chead->ch_free);
|
INSQ(cnk, chead->ch_free);
|
||||||
chead->ch_nfree++;
|
chead->ch_nfree++;
|
||||||
|
|
||||||
/* If chunk is grouped, remove from group.
|
/* If chunk is grouped, remove from group.
|
||||||
|
|
@ -504,13 +504,13 @@ unchunk (void *ptr)
|
||||||
ent = cnk->c_grpent;
|
ent = cnk->c_grpent;
|
||||||
if (ent) {
|
if (ent) {
|
||||||
grp = ent->ce_grp;
|
grp = ent->ce_grp;
|
||||||
DELQ (ent, grp->cg_ent, chunk_grpent_t *);
|
DELQ(ent, grp->cg_ent, chunk_grpent_t *);
|
||||||
unchunk (ent);
|
unchunk(ent);
|
||||||
cnk->c_grpent = NULL;
|
cnk->c_grpent = NULL;
|
||||||
|
|
||||||
/* Group empty? */
|
/* Group empty? */
|
||||||
if (!dont_unchunk_group && !grp->cg_ent) {
|
if (!dont_unchunk_group && !grp->cg_ent) {
|
||||||
DELQ (grp, chunk_grp, chunk_group_t *);
|
DELQ(grp, chunk_grp, chunk_group_t *);
|
||||||
unchunk(grp->cg_name);
|
unchunk(grp->cg_name);
|
||||||
unchunk(grp);
|
unchunk(grp);
|
||||||
}
|
}
|
||||||
|
|
@ -528,7 +528,7 @@ unchunk (void *ptr)
|
||||||
* unchunk_group() - Release all group chunks.
|
* unchunk_group() - Release all group chunks.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
unchunk_group (const char *name)
|
unchunk_group(const char *name)
|
||||||
{
|
{
|
||||||
chunk_group_t *tmp;
|
chunk_group_t *tmp;
|
||||||
chunk_group_t *grp = NULL;
|
chunk_group_t *grp = NULL;
|
||||||
|
|
@ -542,7 +542,7 @@ unchunk_group (const char *name)
|
||||||
if (chunk_grp) {
|
if (chunk_grp) {
|
||||||
tmp = chunk_grp;
|
tmp = chunk_grp;
|
||||||
do {
|
do {
|
||||||
if (!strcmp (tmp->cg_name, name)) {
|
if (!strcmp(tmp->cg_name, name)) {
|
||||||
grp = tmp;
|
grp = tmp;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -560,16 +560,16 @@ unchunk_group (const char *name)
|
||||||
dont_unchunk_group = 1;
|
dont_unchunk_group = 1;
|
||||||
while (grp->cg_ent) {
|
while (grp->cg_ent) {
|
||||||
cnk = grp->cg_ent->ce_cnk;
|
cnk = grp->cg_ent->ce_cnk;
|
||||||
unchunk ((chunk_t *)(((char *)cnk) + sizeof (chunk_t)));
|
unchunk((chunk_t *)(((char *)cnk) + sizeof(chunk_t)));
|
||||||
}
|
}
|
||||||
dont_unchunk_group = 0;
|
dont_unchunk_group = 0;
|
||||||
|
|
||||||
|
|
||||||
/* Remove group from list and free it
|
/* Remove group from list and free it
|
||||||
*/
|
*/
|
||||||
DELQ (grp, chunk_grp, chunk_group_t *);
|
DELQ(grp, chunk_grp, chunk_group_t *);
|
||||||
unchunk (grp->cg_name);
|
unchunk(grp->cg_name);
|
||||||
unchunk (grp);
|
unchunk(grp);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -577,9 +577,9 @@ unchunk_group (const char *name)
|
||||||
*/
|
*/
|
||||||
void *
|
void *
|
||||||
#ifdef CHUNK_DIAG
|
#ifdef CHUNK_DIAG
|
||||||
_chunkdup (const void *ptr, size_t len, const char *name, const char *file, int line)
|
_chunkdup(const void *ptr, size_t len, const char *name, const char *file, int line)
|
||||||
#else
|
#else
|
||||||
chunkdup (const void *ptr, size_t len, const char *name)
|
chunkdup(const void *ptr, size_t len, const char *name)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
void *new;
|
void *new;
|
||||||
|
|
@ -592,9 +592,9 @@ chunkdup (const void *ptr, size_t len, const char *name)
|
||||||
/* Get new chunk
|
/* Get new chunk
|
||||||
*/
|
*/
|
||||||
#ifdef CHUNK_DIAG
|
#ifdef CHUNK_DIAG
|
||||||
new = _chunk (len, name, file, line);
|
new = _chunk(len, name, file, line);
|
||||||
#else
|
#else
|
||||||
new = chunk (len, name);
|
new = chunk(len, name);
|
||||||
#endif
|
#endif
|
||||||
if (!new)
|
if (!new)
|
||||||
return (void *)NULL;
|
return (void *)NULL;
|
||||||
|
|
@ -610,7 +610,7 @@ chunkdup (const void *ptr, size_t len, const char *name)
|
||||||
* chunksize() - Return size of memory chunk.
|
* chunksize() - Return size of memory chunk.
|
||||||
*/
|
*/
|
||||||
size_t
|
size_t
|
||||||
chunksize (void *ptr)
|
chunksize(void *ptr)
|
||||||
{
|
{
|
||||||
chunk_t *cnk;
|
chunk_t *cnk;
|
||||||
chunk_head_t *chead;
|
chunk_head_t *chead;
|
||||||
|
|
@ -621,7 +621,7 @@ chunksize (void *ptr)
|
||||||
|
|
||||||
/* Rewind pointer to beginning of chunk header
|
/* Rewind pointer to beginning of chunk header
|
||||||
*/
|
*/
|
||||||
cnk = (chunk_t *) (((char *)ptr) - sizeof (chunk_t));
|
cnk = (chunk_t *) (((char *)ptr) - sizeof(chunk_t));
|
||||||
cblk = cnk->c_blk;
|
cblk = cnk->c_blk;
|
||||||
chead = cblk->cb_head;
|
chead = cblk->cb_head;
|
||||||
|
|
||||||
|
|
@ -635,10 +635,10 @@ chunksize (void *ptr)
|
||||||
*/
|
*/
|
||||||
char *
|
char *
|
||||||
#ifdef CHUNK_DIAG
|
#ifdef CHUNK_DIAG
|
||||||
_chunk_strncat (const char *dst, const char *src, size_t n, const char *name,
|
_chunk_strncat(const char *dst, const char *src, size_t n, const char *name,
|
||||||
const char *file, int line)
|
const char *file, int line)
|
||||||
#else
|
#else
|
||||||
chunk_strncat (const char *dst, const char *src, size_t n, const char *name)
|
chunk_strncat(const char *dst, const char *src, size_t n, const char *name)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
size_t len;
|
size_t len;
|
||||||
|
|
@ -651,7 +651,7 @@ chunk_strncat (const char *dst, const char *src, size_t n, const char *name)
|
||||||
#ifdef CHUNK_DIAG
|
#ifdef CHUNK_DIAG
|
||||||
ptr = _rechunk(ptr, len, name, file, line);
|
ptr = _rechunk(ptr, len, name, file, line);
|
||||||
#else
|
#else
|
||||||
ptr = rechunk (ptr, len, name);
|
ptr = rechunk(ptr, len, name);
|
||||||
#endif
|
#endif
|
||||||
if (ptr == NULL)
|
if (ptr == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
@ -670,10 +670,10 @@ chunk_strncat (const char *dst, const char *src, size_t n, const char *name)
|
||||||
*/
|
*/
|
||||||
char *
|
char *
|
||||||
#ifdef CHUNK_DIAG
|
#ifdef CHUNK_DIAG
|
||||||
_chunk_sprintf (const char *name, const char *file,
|
_chunk_sprintf(const char *name, const char *file,
|
||||||
int line, const char *fmt, ...)
|
int line, const char *fmt, ...)
|
||||||
#else
|
#else
|
||||||
chunk_sprintf (const char *name, char *fmt, ...)
|
chunk_sprintf(const char *name, char *fmt, ...)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
size_t len;
|
size_t len;
|
||||||
|
|
@ -683,13 +683,13 @@ chunk_sprintf (const char *name, char *fmt, ...)
|
||||||
/* Calculate formatted string length */
|
/* Calculate formatted string length */
|
||||||
va_start(args, fmt);
|
va_start(args, fmt);
|
||||||
len = vsnprintf(NULL, 0, fmt, args) + 1;
|
len = vsnprintf(NULL, 0, fmt, args) + 1;
|
||||||
va_end (args);
|
va_end(args);
|
||||||
|
|
||||||
/* get chunk */
|
/* get chunk */
|
||||||
#ifdef CHUNK_DIAG
|
#ifdef CHUNK_DIAG
|
||||||
str = _chunk (len, name, file, line);
|
str = _chunk(len, name, file, line);
|
||||||
#else
|
#else
|
||||||
str = chunk (len, name);
|
str = chunk(len, name);
|
||||||
#endif
|
#endif
|
||||||
if (str == NULL)
|
if (str == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
@ -697,7 +697,7 @@ chunk_sprintf (const char *name, char *fmt, ...)
|
||||||
/* Format string */
|
/* Format string */
|
||||||
va_start(args, fmt);
|
va_start(args, fmt);
|
||||||
len = vsnprintf(str, len, fmt, args);
|
len = vsnprintf(str, len, fmt, args);
|
||||||
va_end (args);
|
va_end(args);
|
||||||
|
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
@ -756,7 +756,7 @@ chunk_check(FILE *fout, const char *name)
|
||||||
if (chunk_grp) {
|
if (chunk_grp) {
|
||||||
tmp = chunk_grp;
|
tmp = chunk_grp;
|
||||||
do {
|
do {
|
||||||
if (!strcmp (tmp->cg_name, name)) {
|
if (!strcmp(tmp->cg_name, name)) {
|
||||||
grp = tmp;
|
grp = tmp;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -64,7 +64,7 @@
|
||||||
*
|
*
|
||||||
* Alternative for xmlkeyfmt would be eg:
|
* Alternative for xmlkeyfmt would be eg:
|
||||||
* RESTCONF: /interfaces/interface=%s/ipv4/address/ip=%s (used)
|
* RESTCONF: /interfaces/interface=%s/ipv4/address/ip=%s (used)
|
||||||
* XPATH: /interfaces/interface[name=%s]/ipv4/address/[ip=%s]
|
* XPATH: /interfaces/interface[name='%s']/ipv4/address/[ip'=%s']
|
||||||
*
|
*
|
||||||
* Paths through the code (for coverage)
|
* Paths through the code (for coverage)
|
||||||
* cli_callback_generate +----------------+
|
* cli_callback_generate +----------------+
|
||||||
|
|
@ -375,7 +375,7 @@ get(char *dbname,
|
||||||
arg = valvec[j++];
|
arg = valvec[j++];
|
||||||
if (uri_percent_decode(arg, &argdec) < 0)
|
if (uri_percent_decode(arg, &argdec) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
cprintf(cb, "[%s=%s]", cv_string_get(cvi), argdec);
|
cprintf(cb, "[%s='%s']", cv_string_get(cvi), argdec);
|
||||||
free(argdec);
|
free(argdec);
|
||||||
argdec=NULL;
|
argdec=NULL;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -436,7 +436,7 @@ db_regexp(char *file,
|
||||||
goto quit;
|
goto quit;
|
||||||
}
|
}
|
||||||
pair = &newpairs[npairs];
|
pair = &newpairs[npairs];
|
||||||
memset (pair, 0, sizeof(*pair));
|
memset(pair, 0, sizeof(*pair));
|
||||||
|
|
||||||
pair->dp_key = chunk_sprintf(label, "%s", key);
|
pair->dp_key = chunk_sprintf(label, "%s", key);
|
||||||
if (regexp)
|
if (regexp)
|
||||||
|
|
@ -451,7 +451,7 @@ db_regexp(char *file,
|
||||||
}
|
}
|
||||||
if ( ! noval) {
|
if ( ! noval) {
|
||||||
if (vlen){
|
if (vlen){
|
||||||
pair->dp_val = chunkdup (val, vlen, label);
|
pair->dp_val = chunkdup(val, vlen, label);
|
||||||
if (pair->dp_val == NULL) {
|
if (pair->dp_val == NULL) {
|
||||||
clicon_err(OE_DB, errno, "%s: chunkdup", __FUNCTION__);
|
clicon_err(OE_DB, errno, "%s: chunkdup", __FUNCTION__);
|
||||||
goto quit;
|
goto quit;
|
||||||
|
|
|
||||||
|
|
@ -63,8 +63,6 @@ OBJS = $(SRC:.c=.o)
|
||||||
|
|
||||||
all: $(PLUGIN)
|
all: $(PLUGIN)
|
||||||
|
|
||||||
-include $(DESTDIR)$(datarootdir)/clixon/clixon.mk
|
|
||||||
|
|
||||||
$(PLUGIN): $(SRC)
|
$(PLUGIN): $(SRC)
|
||||||
ifeq ($(HOST_VENDOR),apple)
|
ifeq ($(HOST_VENDOR),apple)
|
||||||
$(CC) $(CPPFLAGS) $(INCLUDES) $(CFLAGS) $(LDFLAGS) -shared -undefined dynamic_lookup -o $@ -lc $^ $(LIBS)
|
$(CC) $(CPPFLAGS) $(INCLUDES) $(CFLAGS) $(LDFLAGS) -shared -undefined dynamic_lookup -o $@ -lc $^ $(LIBS)
|
||||||
|
|
|
||||||
|
|
@ -281,7 +281,8 @@ text_setopt(xmldb_handle xh,
|
||||||
else if (strcmp(value,"json")==0)
|
else if (strcmp(value,"json")==0)
|
||||||
th->th_format = "json";
|
th->th_format = "json";
|
||||||
else{
|
else{
|
||||||
clicon_err(OE_PLUGIN, 0, "Option %s unrecognized format: %s", optname, value);
|
clicon_err(OE_PLUGIN, 0, "Option %s unrecognized format: %s",
|
||||||
|
optname, (char*)value);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -473,7 +474,7 @@ text_get(xmldb_handle xh,
|
||||||
} /* xt == NULL */
|
} /* xt == NULL */
|
||||||
/* Here xt looks like: <config>...</config> */
|
/* Here xt looks like: <config>...</config> */
|
||||||
|
|
||||||
if (xpath_vec(xt, xpath?xpath:"/", &xvec, &xlen) < 0)
|
if (xpath_vec(xt, "%s", &xvec, &xlen, xpath?xpath:"/") < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
/* If vectors are specified then mark the nodes found with all ancestors
|
/* If vectors are specified then mark the nodes found with all ancestors
|
||||||
|
|
@ -806,7 +807,8 @@ text_modify_top(cxobj *x0,
|
||||||
x1cname = xml_name(x1c);
|
x1cname = xml_name(x1c);
|
||||||
/* Get yang spec of the child */
|
/* Get yang spec of the child */
|
||||||
if ((yc = yang_find_topnode(yspec, x1cname, YC_DATANODE)) == NULL){
|
if ((yc = yang_find_topnode(yspec, x1cname, YC_DATANODE)) == NULL){
|
||||||
clicon_err(OE_YANG, ENOENT, "XML node %s/%s has no corresponding yang specification (Invalid XML or wrong Yang spec?", x1, x1cname);
|
clicon_err(OE_YANG, ENOENT, "XML node %s/%s has no corresponding yang specification (Invalid XML or wrong Yang spec?",
|
||||||
|
xml_name(x1), x1cname);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
/* See if there is a corresponding node in the base tree */
|
/* See if there is a corresponding node in the base tree */
|
||||||
|
|
|
||||||
94
doc/FAQ.md
94
doc/FAQ.md
|
|
@ -1,4 +1,4 @@
|
||||||
i# Clixon FAQ
|
# Clixon FAQ
|
||||||
|
|
||||||
## What is Clixon?
|
## What is Clixon?
|
||||||
|
|
||||||
|
|
@ -24,7 +24,7 @@ Clixon is written in C. The plugins are written in C. The CLI
|
||||||
specification uses cligen (http://cligen.se)
|
specification uses cligen (http://cligen.se)
|
||||||
|
|
||||||
## How to best understand Clixon?
|
## How to best understand Clixon?
|
||||||
Run the Clixon example, in the example directory.
|
Run the Clixon example, in the [example](../example) directory.
|
||||||
|
|
||||||
## How do you build and install Clixon (and the example)?
|
## How do you build and install Clixon (and the example)?
|
||||||
Clixon:
|
Clixon:
|
||||||
|
|
@ -41,14 +41,25 @@ The example:
|
||||||
sudo make install
|
sudo make install
|
||||||
```
|
```
|
||||||
|
|
||||||
## Do I need to setup anything?
|
## Do I need to setup anything? (IMPORTANT)
|
||||||
|
|
||||||
The config demon requires a valid group to create a server UNIX socket.
|
The config demon requires a valid group to create a server UNIX socket.
|
||||||
Define a valid CLICON_SOCK_GROUP in the config file or via the -g option
|
Define a valid CLICON_SOCK_GROUP in the config file or via the -g option
|
||||||
or create the group and add the user to it. The default group is 'clicon'.
|
or create the group and add the user to it. The default group is 'clicon'.
|
||||||
|
Add yourself and www-data, if you intend to use restconf.
|
||||||
|
|
||||||
On linux:
|
On linux:
|
||||||
|
```
|
||||||
sudo groupadd clicon
|
sudo groupadd clicon
|
||||||
sudo usermod -a -G clicon user
|
sudo usermod -a -G clicon <user>
|
||||||
|
sudo usermod -a -G clicon www-data
|
||||||
|
```
|
||||||
|
|
||||||
|
Verify:
|
||||||
|
```
|
||||||
|
grep clicon /etc/group
|
||||||
|
clicon:x:1001:<user>,www-data
|
||||||
|
```
|
||||||
|
|
||||||
## What about reference documentation?
|
## What about reference documentation?
|
||||||
Clixon uses Doxygen for reference documentation.
|
Clixon uses Doxygen for reference documentation.
|
||||||
|
|
@ -90,20 +101,14 @@ You can change where CLixon looks for the configuration FILE as follows:
|
||||||
- FILE is /usr/local/etc/clixon.xml
|
- FILE is /usr/local/etc/clixon.xml
|
||||||
|
|
||||||
## Can I run Clixon as docker containers?
|
## Can I run Clixon as docker containers?
|
||||||
Yes, the example works as docker containers as well. backend and cli needs a
|
|
||||||
common file-system so they need to run as a composed pair.
|
Yes, the example works as docker containers as well. There should be a
|
||||||
|
prepared container in docker hib for the example where the backend and
|
||||||
|
CLI is bundled.
|
||||||
```
|
```
|
||||||
cd example/docker
|
sudo docker run -ti --rm olofhagsand/clixon_example
|
||||||
make docker # Prepares /data as shared file-system mount
|
|
||||||
run.sh # Starts an example backend and a cli
|
|
||||||
```
|
```
|
||||||
The containers are by default downloaded from dockerhib, but you may
|
Look in the example documentation for more info.
|
||||||
build the containers locally:
|
|
||||||
```
|
|
||||||
cd docker
|
|
||||||
make docker
|
|
||||||
```
|
|
||||||
You may also push the containers with 'make push' but you may then consider changing the image name in the makefile.
|
|
||||||
|
|
||||||
## How do I use netconf?
|
## How do I use netconf?
|
||||||
|
|
||||||
|
|
@ -127,7 +132,25 @@ You can access clixon via REST API using restconf, such as using
|
||||||
curl. GET, PUT, POST are supported.
|
curl. GET, PUT, POST are supported.
|
||||||
|
|
||||||
You need a web-server, such as nginx, and start a restconf fcgi
|
You need a web-server, such as nginx, and start a restconf fcgi
|
||||||
daemon, clixon_restconf. Read more in the restconf docs.
|
daemon, clixon_restconf.
|
||||||
|
|
||||||
|
For example, using nginx, install, and edit config file: /etc/nginx/sites-available/default:
|
||||||
|
```
|
||||||
|
server {
|
||||||
|
...
|
||||||
|
location /restconf {
|
||||||
|
root /usr/share/nginx/html/restconf;
|
||||||
|
fastcgi_pass unix:/www-data/fastcgi_restconf.sock;
|
||||||
|
include fastcgi_params;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
Start nginx daemon
|
||||||
|
```
|
||||||
|
sudo /etc/init.d/nginx start
|
||||||
|
```
|
||||||
|
|
||||||
|
Read more in the restconf docs.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
```
|
```
|
||||||
|
|
@ -178,6 +201,11 @@ You may also add a default method in the configuration file:
|
||||||
</config>
|
</config>
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Can I use systemd with Clixon?
|
||||||
|
|
||||||
|
Yes. Systemd example files are provide for the backend and the
|
||||||
|
restconf daemon as part of the [example](../example/systemd).
|
||||||
|
|
||||||
## How can I add extra XML?
|
## How can I add extra XML?
|
||||||
|
|
||||||
There are two ways to add extra XML to running database after start. Note that this XML is not "committed" into running.
|
There are two ways to add extra XML to running database after start. Note that this XML is not "committed" into running.
|
||||||
|
|
@ -342,5 +370,35 @@ plugin_credentials(clicon_handle h,
|
||||||
|
|
||||||
To authenticate, the callback needs to return the value 1 and supply a username.
|
To authenticate, the callback needs to return the value 1 and supply a username.
|
||||||
|
|
||||||
See [../apps/example/example_restconf.c] plugin_credentials() for
|
See [../apps/example/example_restconf.c] example_restconf_credentials() for
|
||||||
an example of HTTP basic auth.
|
an example of HTTP basic auth.
|
||||||
|
|
||||||
|
## How do I write a CLI translator function?
|
||||||
|
|
||||||
|
The CLI can perform variable translation. This is useful if you want to
|
||||||
|
prcess the input, such as hashing, encrypting or in other way
|
||||||
|
translate the input.
|
||||||
|
|
||||||
|
Yang example:
|
||||||
|
```
|
||||||
|
list translate{
|
||||||
|
leaf value{
|
||||||
|
type string;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
CLI specification:
|
||||||
|
```
|
||||||
|
translate value (<value:string translate:incstr()>),cli_set("/translate/value");
|
||||||
|
```
|
||||||
|
|
||||||
|
If you run this example using the `incstr()` function which increments the characters in the input, you get this result:
|
||||||
|
```
|
||||||
|
cli> translate value HAL
|
||||||
|
cli> show configuration
|
||||||
|
translate {
|
||||||
|
value IBM;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
You can perform translation on any type, not only strings.
|
||||||
|
|
@ -31,19 +31,41 @@
|
||||||
# ***** END LICENSE BLOCK *****
|
# ***** END LICENSE BLOCK *****
|
||||||
#
|
#
|
||||||
|
|
||||||
FROM ubuntu:14.04
|
FROM debian
|
||||||
# 12.04
|
|
||||||
MAINTAINER Olof Hagsand <olof@hagsand.se>
|
MAINTAINER Olof Hagsand <olof@hagsand.se>
|
||||||
ENV DEBIAN_FRONTEND noninteractive
|
ENV DEBIAN_FRONTEND noninteractive
|
||||||
RUN apt-get update && apt-get install -y libqdbm-dev
|
|
||||||
|
RUN apt-get update && apt-get install -y \
|
||||||
|
git make gcc flex bison \
|
||||||
|
libfcgi-dev \
|
||||||
|
libcurl4-openssl-dev
|
||||||
|
|
||||||
|
|
||||||
RUN groupadd clicon
|
RUN groupadd clicon
|
||||||
COPY libcligen.so.@CLIGEN_VERSION@ /usr/lib/
|
|
||||||
COPY libclixon.so.@CLIXON_VERSION_MAJOR@ /usr/lib/
|
# Create a directory to hold source-code, dependencies etc
|
||||||
COPY libclixon_cli.so.@CLIXON_VERSION_MAJOR@ /usr/lib/
|
RUN mkdir /clixon
|
||||||
COPY clixon_cli /usr/bin/
|
WORKDIR /clixon
|
||||||
|
|
||||||
|
# Clone cligen and clixon
|
||||||
|
RUN git clone https://github.com/olofhagsand/cligen.git
|
||||||
|
RUN git clone https://github.com/clicon/clixon.git
|
||||||
|
|
||||||
|
# Build cligen
|
||||||
|
WORKDIR /clixon/cligen
|
||||||
|
RUN ./configure
|
||||||
|
RUN make
|
||||||
|
RUN make install
|
||||||
|
|
||||||
|
# Build clixon
|
||||||
|
WORKDIR /clixon/clixon
|
||||||
|
RUN git checkout -b develop origin/develop
|
||||||
|
RUN ./configure
|
||||||
|
RUN make
|
||||||
|
RUN make install
|
||||||
|
RUN make install-include
|
||||||
|
|
||||||
RUN ldconfig
|
RUN ldconfig
|
||||||
CMD ["/usr/bin/clixon_cli", "-f", "/data/clixon.conf"]
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -38,46 +38,33 @@ CFLAGS = @CFLAGS@
|
||||||
LDFLAGS = @LDFLAGS@
|
LDFLAGS = @LDFLAGS@
|
||||||
LIBS = @LIBS@
|
LIBS = @LIBS@
|
||||||
|
|
||||||
|
# Change this
|
||||||
|
IMAGE = olofhagsand/clixon
|
||||||
|
|
||||||
SHELL = /bin/sh
|
SHELL = /bin/sh
|
||||||
|
|
||||||
SUBDIRS = cli backend netconf
|
|
||||||
|
|
||||||
.PHONY: all clean depend install $(SUBDIRS) docker push
|
.PHONY: all clean depend install docker push
|
||||||
|
|
||||||
all: $(SUBDIRS)
|
all:
|
||||||
|
@echo "Run make docker to build docker image"
|
||||||
depend:
|
|
||||||
for i in $(SUBDIRS); \
|
|
||||||
do (cd $$i; $(MAKE) $(MFLAGS) $@); done
|
|
||||||
|
|
||||||
$(SUBDIRS):
|
|
||||||
(cd $@; $(MAKE) $(MFLAGS) all)
|
|
||||||
|
|
||||||
install-include:
|
|
||||||
for i in $(SUBDIRS); \
|
|
||||||
do (cd $$i ; $(MAKE) $(MFLAGS) $@); done;
|
|
||||||
|
|
||||||
install:
|
|
||||||
for i in $(SUBDIRS); \
|
|
||||||
do (cd $$i; $(MAKE) $(MFLAGS) $@); done
|
|
||||||
|
|
||||||
uninstall:
|
|
||||||
for i in $(SUBDIRS); \
|
|
||||||
do (cd $$i; $(MAKE) $(MFLAGS) $@); done
|
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
for i in $(SUBDIRS); \
|
|
||||||
do (cd $$i; $(MAKE) $(MFLAGS) $@); done
|
|
||||||
|
|
||||||
distclean: clean
|
distclean: clean
|
||||||
rm -f Makefile *~ .depend
|
rm -f Makefile *~ .depend
|
||||||
for i in $(SUBDIRS); \
|
|
||||||
do (cd $$i; $(MAKE) $(MFLAGS) $@); done
|
|
||||||
|
|
||||||
docker:
|
docker:
|
||||||
for i in $(SUBDIRS); \
|
sudo docker build -t $(IMAGE) .
|
||||||
do (cd $$i && $(MAKE) $(MFLAGS) $@); done
|
|
||||||
|
|
||||||
push:
|
push:
|
||||||
for i in $(SUBDIRS); \
|
sudo docker push $(IMAGE)
|
||||||
do (cd $$i && $(MAKE) $(MFLAGS) $@); done
|
|
||||||
|
depend:
|
||||||
|
|
||||||
|
install-include:
|
||||||
|
|
||||||
|
install:
|
||||||
|
|
||||||
|
uninstall:
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,12 +0,0 @@
|
||||||
This dir is not updated
|
|
||||||
|
|
||||||
This dir contains docker code - how to build clixon as docker containers
|
|
||||||
cli Build olofhagsand/clixon_cli container
|
|
||||||
backend Build olofhagsand/clixon_backend container
|
|
||||||
netconf Build olofhagsand/clixon_netconf container
|
|
||||||
|
|
||||||
Perform the build by 'make docker'.
|
|
||||||
You may also do 'make push' if you want to push the image, but you may then consider changing the image name (in the makefile:s).
|
|
||||||
|
|
||||||
You may run the container directly by going directly to example and
|
|
||||||
the docker runtime scripts there
|
|
||||||
19
docker/README.md
Normal file
19
docker/README.md
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
# Clixon base docker image
|
||||||
|
|
||||||
|
This directory contains code for building and pushing a Clixon docker
|
||||||
|
container. By default it is pushed to olofhagsand/clixon, but you can change
|
||||||
|
the IMAGE in Makefile.in and push it to another name.
|
||||||
|
|
||||||
|
The clixon docker image is a base image that can be used to build
|
||||||
|
clixon applications. It has all the whole code for a clixon release
|
||||||
|
which it downloads from git - it does not use local code.
|
||||||
|
|
||||||
|
See example/docker for how to build a docker application using the base image.
|
||||||
|
|
||||||
|
Build and push
|
||||||
|
==============
|
||||||
|
Perform the build by 'make docker'.
|
||||||
|
You may also do 'make push' if you want to push the image, but you may then consider changing the image name (in the makefile:s).
|
||||||
|
|
||||||
|
You may run the container directly by going directly to example and
|
||||||
|
the docker runtime scripts there
|
||||||
|
|
@ -1,6 +0,0 @@
|
||||||
Ensure that cligen and clixon has been built and installed.
|
|
||||||
sudo make docker
|
|
||||||
make push
|
|
||||||
|
|
||||||
Then go to example and run the example as a docker container
|
|
||||||
|
|
||||||
|
|
@ -1,76 +0,0 @@
|
||||||
#
|
|
||||||
# ***** BEGIN LICENSE BLOCK *****
|
|
||||||
#
|
|
||||||
# Copyright (C) 2009-2018 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 *****
|
|
||||||
#
|
|
||||||
VPATH = @srcdir@
|
|
||||||
prefix = @prefix@
|
|
||||||
exec_prefix = @exec_prefix@
|
|
||||||
srcdir = @srcdir@
|
|
||||||
top_srcdir = @top_srcdir@
|
|
||||||
prefix = @prefix@
|
|
||||||
bindir = @bindir@
|
|
||||||
sbindir = @sbindir@
|
|
||||||
libdir = @libdir@
|
|
||||||
includedir = @includedir@
|
|
||||||
datarootdir = @datarootdir@
|
|
||||||
# You may consider changing this
|
|
||||||
image = olofhagsand/clixon_cli
|
|
||||||
|
|
||||||
all:
|
|
||||||
@echo "Run make docker to build docker image"
|
|
||||||
clean:
|
|
||||||
|
|
||||||
distclean: clean
|
|
||||||
rm -f Makefile *~ .depend libcligen* libclixon* clixon_cli Dockerfile
|
|
||||||
|
|
||||||
# Kind of reverse install, could have copied from src dir,...
|
|
||||||
.PHONY: docker push
|
|
||||||
docker:
|
|
||||||
cp $(DESTDIR)$(libdir)/libcligen.so.@CLIGEN_VERSION@ .
|
|
||||||
cp $(DESTDIR)$(libdir)/libclixon.so.@CLIXON_VERSION_MAJOR@ .
|
|
||||||
cp $(DESTDIR)$(libdir)/libclixon_cli.so.@CLIXON_VERSION_MAJOR@ .
|
|
||||||
cp $(DESTDIR)$(bindir)/clixon_cli .
|
|
||||||
sudo docker build -t $(image) .
|
|
||||||
|
|
||||||
push:
|
|
||||||
sudo docker push $(image)
|
|
||||||
|
|
||||||
install:
|
|
||||||
|
|
||||||
uninstall:
|
|
||||||
|
|
||||||
install-include:
|
|
||||||
|
|
||||||
depend:
|
|
||||||
# $(CC) $(DEPENDFLAGS) $(INCLUDES) $(CFLAGS) -MM $(SRC) > .depend
|
|
||||||
|
|
||||||
#include .depend
|
|
||||||
|
|
||||||
|
|
@ -1,6 +0,0 @@
|
||||||
Ensure that cligen and clixon has been built and installed.
|
|
||||||
sudo make docker
|
|
||||||
make push
|
|
||||||
|
|
||||||
Then go to example and run the example as a docker container
|
|
||||||
|
|
||||||
|
|
@ -1,52 +0,0 @@
|
||||||
#
|
|
||||||
# ***** BEGIN LICENSE BLOCK *****
|
|
||||||
#
|
|
||||||
# Copyright (C) 2009-2018 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 *****
|
|
||||||
#
|
|
||||||
|
|
||||||
FROM ubuntu:14.04
|
|
||||||
# 12.04
|
|
||||||
MAINTAINER Olof Hagsand <olof@hagsand.se>
|
|
||||||
ENV DEBIAN_FRONTEND noninteractive
|
|
||||||
RUN apt-get update && apt-get install -y libqdbm-dev
|
|
||||||
RUN groupadd clicon
|
|
||||||
COPY libcligen.so.@CLIGEN_VERSION@ /usr/lib/
|
|
||||||
COPY libclixon.so.@CLIXON_VERSION_MAJOR@ /usr/lib/
|
|
||||||
COPY libclixon_netconf.so.@CLIXON_VERSION_MAJOR@ /usr/lib/
|
|
||||||
COPY clixon_netconf /usr/bin/
|
|
||||||
RUN ldconfig
|
|
||||||
CMD ["/usr/bin/clixon_netconf", "-f", "/data/clixon.conf"]
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,76 +0,0 @@
|
||||||
#
|
|
||||||
# ***** BEGIN LICENSE BLOCK *****
|
|
||||||
#
|
|
||||||
# Copyright (C) 2009-2018 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 *****
|
|
||||||
#
|
|
||||||
VPATH = @srcdir@
|
|
||||||
prefix = @prefix@
|
|
||||||
exec_prefix = @exec_prefix@
|
|
||||||
srcdir = @srcdir@
|
|
||||||
top_srcdir = @top_srcdir@
|
|
||||||
prefix = @prefix@
|
|
||||||
bindir = @bindir@
|
|
||||||
sbindir = @sbindir@
|
|
||||||
libdir = @libdir@
|
|
||||||
includedir = @includedir@
|
|
||||||
datarootdir = @datarootdir@
|
|
||||||
# You may consider changing this
|
|
||||||
image = olofhagsand/clixon_netconf
|
|
||||||
|
|
||||||
all:
|
|
||||||
@echo "Run make docker to build docker image"
|
|
||||||
clean:
|
|
||||||
|
|
||||||
distclean: clean
|
|
||||||
rm -f Makefile *~ .depend libcligen* libclixon* clixon_netconf Dockerfile
|
|
||||||
|
|
||||||
# Kind of reverse install, could have copied from src dir,...
|
|
||||||
.PHONY: docker push
|
|
||||||
docker:
|
|
||||||
cp $(DESTDIR)$(libdir)/libcligen.so.@CLIGEN_VERSION@ .
|
|
||||||
cp $(DESTDIR)$(libdir)/libclixon.so.@CLIXON_VERSION_MAJOR@ .
|
|
||||||
cp $(DESTDIR)$(libdir)/libclixon_netconf.so.@CLIXON_VERSION_MAJOR@ .
|
|
||||||
cp $(DESTDIR)$(bindir)/clixon_netconf .
|
|
||||||
sudo docker build -t $(image) .
|
|
||||||
|
|
||||||
push:
|
|
||||||
sudo docker push $(image)
|
|
||||||
|
|
||||||
install:
|
|
||||||
|
|
||||||
uninstall:
|
|
||||||
|
|
||||||
install-include:
|
|
||||||
|
|
||||||
depend:
|
|
||||||
# $(CC) $(DEPENDFLAGS) $(INCLUDES) $(CFLAGS) -MM $(SRC) > .depend
|
|
||||||
|
|
||||||
#include .depend
|
|
||||||
|
|
||||||
|
|
@ -1,6 +0,0 @@
|
||||||
Ensure that cligen and clixon has been built and installed.
|
|
||||||
sudo make docker
|
|
||||||
make push
|
|
||||||
|
|
||||||
Then go to example and run the example as a docker container
|
|
||||||
|
|
||||||
|
|
@ -31,21 +31,29 @@
|
||||||
# ***** END LICENSE BLOCK *****
|
# ***** END LICENSE BLOCK *****
|
||||||
#
|
#
|
||||||
|
|
||||||
FROM ubuntu:14.04
|
FROM olofhagsand/clixon
|
||||||
# 12.04
|
|
||||||
MAINTAINER Olof Hagsand <olof@hagsand.se>
|
MAINTAINER Olof Hagsand <olof@hagsand.se>
|
||||||
ENV DEBIAN_FRONTEND noninteractive
|
|
||||||
RUN apt-get update && apt-get install -y libqdbm-dev
|
RUN apt-get update && apt-get install -y \
|
||||||
RUN groupadd clicon
|
procps # ps for debugging
|
||||||
COPY libcligen.so.@CLIGEN_VERSION@ /usr/lib/
|
# Create a directory to hold source-code, dependencies etc
|
||||||
COPY libclixon.so.@CLIXON_VERSION_MAJOR@ /usr/lib/
|
RUN mkdir /example
|
||||||
COPY libclixon_backend.so.@CLIXON_VERSION_MAJOR@ /usr/lib/
|
WORKDIR /example
|
||||||
COPY clixon_backend /usr/sbin/
|
|
||||||
RUN ldconfig
|
# Clone clixon (again) since example application is there.
|
||||||
RUN sudo groupadd clixon
|
# Replace this with your application
|
||||||
CMD ["/usr/sbin/clixon_backend", "-F", "-f", "/data/clixon.conf"]
|
RUN git clone https://github.com/clicon/clixon.git
|
||||||
|
|
||||||
|
# Build clixon
|
||||||
|
WORKDIR /example/clixon
|
||||||
|
RUN git checkout -b develop origin/develop
|
||||||
|
RUN ./configure
|
||||||
|
WORKDIR /example/clixon/example
|
||||||
|
RUN make
|
||||||
|
RUN make install
|
||||||
|
RUN install example.xml /usr/local/etc/clixon.xml
|
||||||
|
|
||||||
|
CMD /usr/local/sbin/clixon_backend && /usr/local/bin/clixon_cli
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -37,8 +37,13 @@ prefix = @prefix@
|
||||||
bindir = @bindir@
|
bindir = @bindir@
|
||||||
includedir = @includedir@
|
includedir = @includedir@
|
||||||
datarootdir = @datarootdir@
|
datarootdir = @datarootdir@
|
||||||
|
sysconfdir = @sysconfdir@
|
||||||
|
datarootdir = @datarootdir@
|
||||||
|
localstatedir = @localstatedir@
|
||||||
|
libdir = @exec_prefix@/lib
|
||||||
|
|
||||||
APPNAME = example
|
APPNAME = example
|
||||||
|
|
||||||
CC = @CC@
|
CC = @CC@
|
||||||
CFLAGS = @CFLAGS@ -rdynamic -fPIC
|
CFLAGS = @CFLAGS@ -rdynamic -fPIC
|
||||||
INSTALLFLAGS = @INSTALLFLAGS@
|
INSTALLFLAGS = @INSTALLFLAGS@
|
||||||
|
|
@ -51,12 +56,14 @@ CLI_PLUGIN = $(APPNAME)_cli.so
|
||||||
NETCONF_PLUGIN = $(APPNAME)_netconf.so
|
NETCONF_PLUGIN = $(APPNAME)_netconf.so
|
||||||
RESTCONF_PLUGIN = $(APPNAME)_restconf.so
|
RESTCONF_PLUGIN = $(APPNAME)_restconf.so
|
||||||
|
|
||||||
|
# Example docker image. PLEASE CHANGE THIS
|
||||||
|
IMAGE = olofhagsand/clixon_example
|
||||||
|
|
||||||
PLUGINS = $(BE_PLUGIN) $(BE2_PLUGIN) $(CLI_PLUGIN) $(NETCONF_PLUGIN) $(RESTCONF_PLUGIN)
|
PLUGINS = $(BE_PLUGIN) $(BE2_PLUGIN) $(CLI_PLUGIN) $(NETCONF_PLUGIN) $(RESTCONF_PLUGIN)
|
||||||
|
|
||||||
all: $(PLUGINS)
|
.PHONY: all clean depend install docker push
|
||||||
|
|
||||||
# Note: clixon.mk has rules for clixon_DBSPECDIR, clixon_SYSCONFDIR, etc used below
|
all: $(PLUGINS)
|
||||||
-include $(DESTDIR)$(datarootdir)/clixon/clixon.mk
|
|
||||||
|
|
||||||
CLISPECS = $(APPNAME)_cli.cli
|
CLISPECS = $(APPNAME)_cli.cli
|
||||||
|
|
||||||
|
|
@ -69,6 +76,7 @@ YANGSPECS += ietf-routing@2014-10-26.yang
|
||||||
YANGSPECS += ietf-ipv4-unicast-routing@2014-10-26.yang
|
YANGSPECS += ietf-ipv4-unicast-routing@2014-10-26.yang
|
||||||
YANGSPECS += ietf-ipv6-unicast-routing@2014-10-26.yang
|
YANGSPECS += ietf-ipv6-unicast-routing@2014-10-26.yang
|
||||||
YANGSPECS += ietf-ipsec@2016-03-09.yang
|
YANGSPECS += ietf-ipsec@2016-03-09.yang
|
||||||
|
YANGSPECS += iana-if-type@2014-05-08.yang
|
||||||
|
|
||||||
# Backend plugin
|
# Backend plugin
|
||||||
BE_SRC = $(APPNAME)_backend.c
|
BE_SRC = $(APPNAME)_backend.c
|
||||||
|
|
@ -105,42 +113,45 @@ OBJS = $(BE_OBJ) $(BE2_OBJ) $(CLI_OBJ) $(NETCONF_OBJ) $(RESTCONF_OBJ)
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f $(PLUGINS) $(OBJS)
|
rm -f $(PLUGINS) $(OBJS)
|
||||||
(cd docker && $(MAKE) $(MFLAGS) $@)
|
|
||||||
|
|
||||||
distclean: clean
|
distclean: clean
|
||||||
rm -f Makefile *~ .depend
|
rm -f Makefile *~ .depend
|
||||||
(cd docker && $(MAKE) $(MFLAGS) $@)
|
|
||||||
|
|
||||||
install: $(YANGSPECS) $(CLISPECS) $(BE_PLUGIN) $(BE2_PLUGIN) $(CLI_PLUGIN) $(NETCONF_PLUGIN) $(RESTCONF_PLUGIN) $(APPNAME).xml
|
install: $(YANGSPECS) $(CLISPECS) $(BE_PLUGIN) $(BE2_PLUGIN) $(CLI_PLUGIN) $(NETCONF_PLUGIN) $(RESTCONF_PLUGIN) $(APPNAME).xml
|
||||||
install -d -m 0755 $(DESTDIR)$(clixon_SYSCONFDIR)
|
install -d -m 0755 $(DESTDIR)$(sysconfdir)
|
||||||
install -m 0644 $(APPNAME).xml $(DESTDIR)$(clixon_SYSCONFDIR)
|
install -m 0644 $(APPNAME).xml $(DESTDIR)$(sysconfdir)
|
||||||
install -d -m 0755 $(DESTDIR)$(clixon_DBSPECDIR)/yang
|
install -d -m 0755 $(DESTDIR)$(datarootdir)/$(APPNAME)/yang
|
||||||
install -m 0644 $(YANGSPECS) $(DESTDIR)$(clixon_DBSPECDIR)/yang
|
install -m 0644 $(YANGSPECS) $(DESTDIR)$(datarootdir)/$(APPNAME)/yang
|
||||||
install -d -m 0755 $(DESTDIR)$(clixon_LIBDIR)/cli
|
install -d -m 0755 $(DESTDIR)$(libdir)/$(APPNAME)/cli
|
||||||
install -m 0644 $(INSTALLFLAGS) $(CLI_PLUGIN) $(DESTDIR)$(clixon_LIBDIR)/cli
|
install -m 0644 $(INSTALLFLAGS) $(CLI_PLUGIN) $(DESTDIR)$(libdir)/$(APPNAME)/cli
|
||||||
install -d -m 0755 $(DESTDIR)$(clixon_LIBDIR)/backend
|
install -d -m 0755 $(DESTDIR)$(libdir)/$(APPNAME)/backend
|
||||||
install -m 0644 $(INSTALLFLAGS) $(BE_PLUGIN) $(BE2_PLUGIN) $(DESTDIR)$(clixon_LIBDIR)/backend
|
install -m 0644 $(INSTALLFLAGS) $(BE_PLUGIN) $(BE2_PLUGIN) $(DESTDIR)$(libdir)/$(APPNAME)/backend
|
||||||
install -d -m 0755 $(DESTDIR)$(clixon_LIBDIR)/netconf
|
install -d -m 0755 $(DESTDIR)$(libdir)/$(APPNAME)/netconf
|
||||||
install -m 0644 $(INSTALLFLAGS) $(NETCONF_PLUGIN) $(DESTDIR)$(clixon_LIBDIR)/netconf
|
install -m 0644 $(INSTALLFLAGS) $(NETCONF_PLUGIN) $(DESTDIR)$(libdir)/$(APPNAME)/netconf
|
||||||
install -d -m 0755 $(DESTDIR)$(clixon_LIBDIR)/restconf
|
install -d -m 0755 $(DESTDIR)$(libdir)/$(APPNAME)/restconf
|
||||||
install -m 0644 $(INSTALLFLAGS) $(RESTCONF_PLUGIN) $(DESTDIR)$(clixon_LIBDIR)/restconf
|
install -m 0644 $(INSTALLFLAGS) $(RESTCONF_PLUGIN) $(DESTDIR)$(libdir)/$(APPNAME)/restconf
|
||||||
install -d -m 0755 $(DESTDIR)$(clixon_LIBDIR)/clispec
|
install -d -m 0755 $(DESTDIR)$(libdir)/$(APPNAME)/clispec
|
||||||
install -m 0644 $(CLISPECS) $(DESTDIR)$(clixon_LIBDIR)/clispec
|
install -m 0644 $(CLISPECS) $(DESTDIR)$(libdir)/$(APPNAME)/clispec
|
||||||
install -d -m 0755 $(DESTDIR)$(clixon_LOCALSTATEDIR)
|
install -d -m 0755 $(DESTDIR)$(localstatedir)/$(APPNAME)
|
||||||
(cd docker && $(MAKE) $(MFLAGS) $@)
|
|
||||||
|
docker:
|
||||||
|
sudo docker build -t $(IMAGE) .
|
||||||
|
|
||||||
|
push:
|
||||||
|
sudo docker push $(IMAGE)
|
||||||
|
|
||||||
uninstall:
|
uninstall:
|
||||||
rm -rf $(DESTDIR)$(clixon_SYSCONFDIR)/$(APPNAME).xml
|
echo "libdir:$(libdir)"
|
||||||
rm -rf $(DESTDIR)$(clixon_DBSPECDIR)
|
echo "libdir2:$(libdir2)"
|
||||||
rm -rf $(DESTDIR)$(clixon_LOCALSTATEDIR)
|
rm -rf $(DESTDIR)$(sysconfdir)/$(APPNAME).xml
|
||||||
rm -rf $(DESTDIR)$(clixon_LIBDIR)
|
rm -rf $(DESTDIR)$(datarootdir)/$(APPNAME)
|
||||||
(cd docker && $(MAKE) $(MFLAGS) $@)
|
rm -rf $(DESTDIR)$(localstatedir)/$(APPNAME)
|
||||||
|
rm -rf $(DESTDIR)$(libdir)/$(APPNAME)
|
||||||
|
|
||||||
install-include:
|
install-include:
|
||||||
|
|
||||||
depend:
|
depend:
|
||||||
$(CC) $(DEPENDFLAGS) $(INCLUDES) $(CFLAGS) -MM $(SRC) > .depend
|
$(CC) $(DEPENDFLAGS) $(INCLUDES) $(CFLAGS) -MM $(SRC) > .depend
|
||||||
(cd docker && $(MAKE) $(MFLAGS) $@)
|
|
||||||
|
|
||||||
#include .depend
|
#include .depend
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,14 +16,20 @@ routing example. It contains the following files:
|
||||||
* example_netconf.c Netconf callback plugin
|
* example_netconf.c Netconf callback plugin
|
||||||
* Makefile.in Example makefile where plugins are built and installed
|
* Makefile.in Example makefile where plugins are built and installed
|
||||||
|
|
||||||
|
|
||||||
## Compile and run
|
## Compile and run
|
||||||
|
|
||||||
|
Before you start,
|
||||||
|
* Make [group setup](../doc/FAQ.md#do-i-need-to-setup-anything-important)
|
||||||
|
* Setup [restconf](../doc/FAQ.md#how-do-i-use-restconf)
|
||||||
|
|
||||||
```
|
```
|
||||||
cd example
|
cd example
|
||||||
make && sudo make install
|
make && sudo make install
|
||||||
```
|
```
|
||||||
Start backend:
|
Start backend:
|
||||||
```
|
```
|
||||||
clixon_backend -f /usr/local/etc/example.xml -I
|
sudo clixon_backend -f /usr/local/etc/example.xml -s init
|
||||||
```
|
```
|
||||||
Edit cli:
|
Edit cli:
|
||||||
```
|
```
|
||||||
|
|
@ -188,6 +194,10 @@ The example contains some stubs for authorization according to [RFC8341(NACM)](h
|
||||||
* A NACM backend plugin reporting the mandatory NACM state variables.
|
* A NACM backend plugin reporting the mandatory NACM state variables.
|
||||||
|
|
||||||
|
|
||||||
|
## Systemd files
|
||||||
|
|
||||||
|
Example systemd files for backend and restconf daemons are found under the systemd directory. Install them under /etc/systemd/system for example.
|
||||||
|
|
||||||
## Run as docker container
|
## Run as docker container
|
||||||
|
|
||||||
(Note not updated)
|
(Note not updated)
|
||||||
|
|
@ -196,5 +206,19 @@ cd docker
|
||||||
# look in README
|
# look in README
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Docker
|
||||||
|
|
||||||
|
Run the example as a docker container as follows:
|
||||||
|
```
|
||||||
|
sudo docker run -ti --rm olofhagsand/clixon_example
|
||||||
|
```
|
||||||
|
|
||||||
|
Build the container and push yourself: First change the IMAGE variable in Makefile (eg to "you/clixon_example). Then build and push:
|
||||||
|
```
|
||||||
|
make docker
|
||||||
|
make push
|
||||||
|
sudo docker run -ti --rm you/clixon_example
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,80 +0,0 @@
|
||||||
#
|
|
||||||
# ***** BEGIN LICENSE BLOCK *****
|
|
||||||
#
|
|
||||||
# Copyright (C) 2009-2018 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 *****
|
|
||||||
#
|
|
||||||
VPATH = @srcdir@
|
|
||||||
srcdir = @srcdir@
|
|
||||||
top_srcdir = @top_srcdir@
|
|
||||||
prefix = @prefix@
|
|
||||||
bindir = @bindir@
|
|
||||||
includedir = @includedir@
|
|
||||||
datarootdir = @datarootdir@
|
|
||||||
|
|
||||||
APPNAME = routing
|
|
||||||
|
|
||||||
all: $(APPNAME).conf
|
|
||||||
|
|
||||||
-include $(DESTDIR)$(datarootdir)/clixon/clixon.mk
|
|
||||||
|
|
||||||
# Kind of reverse install, could have copied from src dir,...
|
|
||||||
.PHONY: docker push
|
|
||||||
docker: $(APPNAME).conf
|
|
||||||
install -d data
|
|
||||||
install -d data/yang
|
|
||||||
install -d data/backend
|
|
||||||
install -d data/cli
|
|
||||||
install -d data/netconf
|
|
||||||
install -d data/clispec
|
|
||||||
install $(APPNAME).conf data/clixon.conf # docker image assumes /data/clixon.conf
|
|
||||||
install ../*.yang data/yang/
|
|
||||||
install ../routing_cli.so data/cli/
|
|
||||||
install ../routing_backend.so data/backend/
|
|
||||||
install ../routing_netconf.so data/netconf/
|
|
||||||
install ../*.cli data/clispec
|
|
||||||
|
|
||||||
clean:
|
|
||||||
rm -f $(APPNAME).conf
|
|
||||||
|
|
||||||
distclean: clean
|
|
||||||
rm -f Makefile *~ .depend
|
|
||||||
rm -rf data
|
|
||||||
|
|
||||||
install:
|
|
||||||
|
|
||||||
uninstall:
|
|
||||||
|
|
||||||
install-include:
|
|
||||||
|
|
||||||
depend:
|
|
||||||
$(CC) $(DEPENDFLAGS) $(INCLUDES) $(CFLAGS) -MM $(SRC) > .depend
|
|
||||||
|
|
||||||
#include .depend
|
|
||||||
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
Run the ietf routing example as docker container.
|
|
||||||
Use the dockerhub container, or alternatively, build clicon as docker images
|
|
||||||
by doing make docker in the top builddir.
|
|
||||||
|
|
||||||
(cd ..; make) # Make example
|
|
||||||
make docker # Create config file and shared file system
|
|
||||||
run.sh # Run a backend and a cli container
|
|
||||||
|
|
@ -1,66 +0,0 @@
|
||||||
# Main YANG module first parsed by parser (in CLICON_YANG_DIR). eg clicon.yang.
|
|
||||||
|
|
||||||
# Location of configuration-file for default values (this file)
|
|
||||||
CLICON_CONFIGFILE /data/clixon.conf
|
|
||||||
# Location of YANG module and submodule files. Only if CLICON_DBSPEC_TYPE is YANG
|
|
||||||
CLICON_YANG_DIR /data/yang
|
|
||||||
# Option used to construct initial yang file:
|
|
||||||
# <module>[@<revision>]
|
|
||||||
# This option is only relevant if CLICON_DBSPEC_TYPE is YANG
|
|
||||||
# CLICON_YANG_MODULE_MAIN clicon
|
|
||||||
# Option used to construct initial yang file:
|
|
||||||
# <module>[@<revision>]
|
|
||||||
# This option is only relevant if CLICON_DBSPEC_TYPE is YANG
|
|
||||||
CLICON_YANG_MODULE_REVISION
|
|
||||||
# Candidate qdbm database
|
|
||||||
CLICON_CANDIDATE_DB /data/candidate_db
|
|
||||||
# Running qdbm database
|
|
||||||
CLICON_RUNNING_DB /data/running_db
|
|
||||||
# Location of backend .so plugins
|
|
||||||
CLICON_BACKEND_DIR /data/backend
|
|
||||||
# Location of netconf (frontend) .so plugins
|
|
||||||
CLICON_NETCONF_DIR /data/netconf
|
|
||||||
# Location of cli frontend .so plugins
|
|
||||||
CLICON_CLI_DIR /data/cli
|
|
||||||
# Location of frontend .cli cligen spec files
|
|
||||||
CLICON_CLISPEC_DIR /data/clispec
|
|
||||||
# Directory where to save configuration commit history (in XML). Snapshots
|
|
||||||
# are saved chronologically
|
|
||||||
CLICON_ARCHIVE_DIR /data
|
|
||||||
# XXX Name of startup configuration file (in XML)
|
|
||||||
CLICON_STARTUP_CONFIG /data/startup-config
|
|
||||||
# Address family for communicating with clixon_backend (UNIX|IPv4|IPv6)
|
|
||||||
CLICON_SOCK_FAMILY UNIX
|
|
||||||
# If family above is AF_UNIX: Unix socket for communicating with clixon_backend
|
|
||||||
# If family above is AF_INET: IPv4 address
|
|
||||||
CLICON_SOCK /data/routing.sock
|
|
||||||
# Inet socket port for communicating with clixon_backend (only IPv4|IPv6)
|
|
||||||
CLICON_SOCK_PORT 4535
|
|
||||||
# Process-id file
|
|
||||||
CLICON_BACKEND_PIDFILE /data/routing.pidfile
|
|
||||||
|
|
||||||
# Save values as XML in database instead of lvec:s.
|
|
||||||
# This is optimized for yang specified applications
|
|
||||||
# But not compatible with key-based application (eg Rost)
|
|
||||||
CLICON_DB_XML 1
|
|
||||||
|
|
||||||
# Startup CLI mode. This should match the CLICON_MODE in your startup clispec file
|
|
||||||
CLICON_CLI_MODE routing
|
|
||||||
|
|
||||||
# Option used to construct initial yang file:
|
|
||||||
# <module>[@<revision>]
|
|
||||||
# This option is only relevant if CLICON_DBSPEC_TYPE is YANG
|
|
||||||
CLICON_YANG_MODULE_MAIN ietf-ip
|
|
||||||
|
|
||||||
# Option used to construct initial yang file:
|
|
||||||
# <module>[@<revision>]
|
|
||||||
# This option is only relevant if CLICON_DBSPEC_TYPE is YANG
|
|
||||||
CLICON_YANG_MODULE_REVISION 2014-06-16
|
|
||||||
|
|
||||||
# Generate code for CLI completion of existing db symbols
|
|
||||||
# CLICON_CLI_GENMODEL_COMPLETION 0
|
|
||||||
CLICON_CLI_GENMODEL_COMPLETION 1
|
|
||||||
|
|
||||||
# How to generate and show CLI syntax: VARS|ALL
|
|
||||||
# CLICON_CLI_GENMODEL_TYPE VARS
|
|
||||||
CLICON_CLI_GENMODEL_TYPE VARS
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
# Start daemon and a cli docker containers .
|
|
||||||
# Note that they have a common file-system at /data
|
|
||||||
#
|
|
||||||
sudo docker run -td --net host -v $(pwd)/data:/data olofhagsand/clixon_backend
|
|
||||||
sudo docker run -ti --rm --net host -v $(pwd)/data:/data olofhagsand/clixon_cli
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,13 +1,33 @@
|
||||||
module example {
|
module example {
|
||||||
prefix ex;
|
prefix ex;
|
||||||
|
import ietf-interfaces {
|
||||||
|
prefix if;
|
||||||
|
}
|
||||||
import ietf-ip {
|
import ietf-ip {
|
||||||
prefix ip;
|
prefix ip;
|
||||||
}
|
}
|
||||||
import ietf-routing {
|
import ietf-routing {
|
||||||
prefix rt;
|
prefix rt;
|
||||||
}
|
}
|
||||||
|
import iana-if-type {
|
||||||
|
prefix ianaift;
|
||||||
|
}
|
||||||
description
|
description
|
||||||
"Example code that includes ietf-ip and ietf-routing";
|
"Example code that includes ietf-ip and ietf-routing";
|
||||||
|
/* Example interface type for tests, local callbacks, etc */
|
||||||
|
identity eth {
|
||||||
|
base if:interface-type;
|
||||||
|
}
|
||||||
|
identity loopback {
|
||||||
|
base if:interface-type;
|
||||||
|
}
|
||||||
|
/* Translation function example - See also example_cli */
|
||||||
|
|
||||||
|
list translate{
|
||||||
|
leaf value{
|
||||||
|
type string;
|
||||||
|
}
|
||||||
|
}
|
||||||
rpc client-rpc {
|
rpc client-rpc {
|
||||||
description "Example local client-side RPC that is processed by the
|
description "Example local client-side RPC that is processed by the
|
||||||
the netconf/restconf and not sent to the backend.
|
the netconf/restconf and not sent to the backend.
|
||||||
|
|
|
||||||
|
|
@ -180,7 +180,7 @@ empty(clicon_handle h, /* Clicon handle */
|
||||||
* Real code would poll state
|
* Real code would poll state
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
plugin_statedata(clicon_handle h,
|
example_statedata(clicon_handle h,
|
||||||
char *xpath,
|
char *xpath,
|
||||||
cxobj *xstate)
|
cxobj *xstate)
|
||||||
{
|
{
|
||||||
|
|
@ -190,7 +190,7 @@ plugin_statedata(clicon_handle h,
|
||||||
/* Example of (static) statedata, real code would poll state */
|
/* Example of (static) statedata, real code would poll state */
|
||||||
if (xml_parse_string("<interfaces-state><interface>"
|
if (xml_parse_string("<interfaces-state><interface>"
|
||||||
"<name>eth0</name>"
|
"<name>eth0</name>"
|
||||||
"<type>eth</type>"
|
"<type>ex:eth</type>"
|
||||||
"<if-index>42</if-index>"
|
"<if-index>42</if-index>"
|
||||||
"</interface></interfaces-state>", NULL, &xstate) < 0)
|
"</interface></interfaces-state>", NULL, &xstate) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -214,14 +214,14 @@ plugin_statedata(clicon_handle h,
|
||||||
* @note This assumes example yang with interfaces/interface
|
* @note This assumes example yang with interfaces/interface
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
plugin_reset(clicon_handle h,
|
example_reset(clicon_handle h,
|
||||||
const char *db)
|
const char *db)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
cxobj *xt = NULL;
|
cxobj *xt = NULL;
|
||||||
|
|
||||||
if (xml_parse_string("<config><interfaces><interface>"
|
if (xml_parse_string("<config><interfaces><interface>"
|
||||||
"<name>lo</name><type>local</type>"
|
"<name>lo</name><type>ex:loopback</type>"
|
||||||
"</interface></interfaces></config>", NULL, &xt) < 0)
|
"</interface></interfaces></config>", NULL, &xt) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
/* Replace parent w fiorst child */
|
/* Replace parent w fiorst child */
|
||||||
|
|
@ -250,7 +250,7 @@ plugin_reset(clicon_handle h,
|
||||||
* can be processed with the standard getopt(3).
|
* can be processed with the standard getopt(3).
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
plugin_start(clicon_handle h,
|
example_start(clicon_handle h,
|
||||||
int argc,
|
int argc,
|
||||||
char **argv)
|
char **argv)
|
||||||
{
|
{
|
||||||
|
|
@ -261,11 +261,11 @@ clixon_plugin_api *clixon_plugin_init(clicon_handle h);
|
||||||
|
|
||||||
static clixon_plugin_api api = {
|
static clixon_plugin_api api = {
|
||||||
"example", /* name */
|
"example", /* name */
|
||||||
clixon_plugin_init, /* init */
|
clixon_plugin_init, /* init - must be called clixon_plugin_init */
|
||||||
plugin_start, /* start */
|
example_start, /* start */
|
||||||
NULL, /* exit */
|
NULL, /* exit */
|
||||||
.ca_reset=plugin_reset, /* reset */
|
.ca_reset=example_reset, /* reset */
|
||||||
.ca_statedata=plugin_statedata, /* statedata */
|
.ca_statedata=example_statedata, /* statedata */
|
||||||
.ca_trans_begin=NULL, /* trans begin */
|
.ca_trans_begin=NULL, /* trans begin */
|
||||||
.ca_trans_validate=transaction_validate,/* trans validate */
|
.ca_trans_validate=transaction_validate,/* trans validate */
|
||||||
.ca_trans_complete=NULL, /* trans complete */
|
.ca_trans_complete=NULL, /* trans complete */
|
||||||
|
|
|
||||||
|
|
@ -114,6 +114,13 @@ static clixon_plugin_api api = {
|
||||||
clixon_plugin_api *
|
clixon_plugin_api *
|
||||||
clixon_plugin_init(clicon_handle h)
|
clixon_plugin_init(clicon_handle h)
|
||||||
{
|
{
|
||||||
|
char *nacm_mode;
|
||||||
|
|
||||||
clicon_debug(1, "%s backend nacm", __FUNCTION__);
|
clicon_debug(1, "%s backend nacm", __FUNCTION__);
|
||||||
|
nacm_mode = clicon_option_str(h, "CLICON_NACM_MODE");
|
||||||
|
if (nacm_mode==NULL || strcmp(nacm_mode, "disabled") == 0){
|
||||||
|
clicon_debug(1, "%s CLICON_NACM_MODE not enabled: example nacm module disabled", __FUNCTION__);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
return &api;
|
return &api;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -67,7 +67,12 @@ mycallback(clicon_handle h, cvec *cvv, cvec *argv)
|
||||||
cli_output(stderr, "arg = %s\n", cv_string_get(cvec_i(argv,0))); /* get string value */
|
cli_output(stderr, "arg = %s\n", cv_string_get(cvec_i(argv,0))); /* get string value */
|
||||||
|
|
||||||
/* Show eth0 interfaces config using XPATH */
|
/* Show eth0 interfaces config using XPATH */
|
||||||
if (clicon_rpc_get_config(h, "running","/interfaces/interface[name=eth0]",
|
if (clicon_rpc_get_config(h, "running",
|
||||||
|
#ifdef COMPAT_XSL
|
||||||
|
"/interfaces/interface[name=eth0]",
|
||||||
|
#else
|
||||||
|
"/interfaces/interface[name='eth0']",
|
||||||
|
#endif
|
||||||
&xret) < 0)
|
&xret) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
|
|
@ -90,17 +95,24 @@ fib_route_rpc(clicon_handle h,
|
||||||
cxobj *xtop = NULL;
|
cxobj *xtop = NULL;
|
||||||
cxobj *xrpc;
|
cxobj *xrpc;
|
||||||
cxobj *xret = NULL;
|
cxobj *xret = NULL;
|
||||||
|
cxobj *xerr;
|
||||||
|
|
||||||
/* User supplied variable in CLI command */
|
/* User supplied variable in CLI command */
|
||||||
instance = cvec_find(cvv, "instance"); /* get a cligen variable from vector */
|
instance = cvec_find(cvv, "instance"); /* get a cligen variable from vector */
|
||||||
/* Create XML for fib-route netconf RPC */
|
/* Create XML for fib-route netconf RPC */
|
||||||
if (xml_parse_va(&xtop, NULL, "<rpc><fib-route><routing-instance-name>%s</routing-instance-name></fib-route></rpc>", cv_string_get(instance)) < 0)
|
if (xml_parse_va(&xtop, NULL, "<rpc username=\"%s\"><fib-route><routing-instance-name>%s</routing-instance-name></fib-route></rpc>",
|
||||||
|
clicon_username_get(h),
|
||||||
|
cv_string_get(instance)) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
/* Skip top-level */
|
/* Skip top-level */
|
||||||
xrpc = xml_child_i(xtop, 0);
|
xrpc = xml_child_i(xtop, 0);
|
||||||
/* Send to backend */
|
/* Send to backend */
|
||||||
if (clicon_rpc_netconf_xml(h, xrpc, &xret, NULL) < 0)
|
if (clicon_rpc_netconf_xml(h, xrpc, &xret, NULL) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
if ((xerr = xpath_first(xret, "//rpc-error")) != NULL){
|
||||||
|
clicon_rpc_generate_error("Get configuration", xerr);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
/* Print result */
|
/* Print result */
|
||||||
xml_print(stdout, xml_child_i(xret, 0));
|
xml_print(stdout, xml_child_i(xret, 0));
|
||||||
retval = 0;
|
retval = 0;
|
||||||
|
|
@ -137,3 +149,21 @@ clixon_plugin_init(clicon_handle h)
|
||||||
|
|
||||||
return &api;
|
return &api;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! Translate function from an original value to a new.
|
||||||
|
* In this case, assume string and increment characters, eg HAL->IBM
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
incstr(cligen_handle h,
|
||||||
|
cg_var *cv)
|
||||||
|
{
|
||||||
|
char *str;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (cv_type_get(cv) != CGV_STRING)
|
||||||
|
return 0;
|
||||||
|
str = cv_string_get(cv);
|
||||||
|
for (i=0; i<strlen(str); i++)
|
||||||
|
str[i]++;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,9 @@ CLICON_MODE="example";
|
||||||
CLICON_PROMPT="%U@%H> ";
|
CLICON_PROMPT="%U@%H> ";
|
||||||
CLICON_PLUGIN="example_cli";
|
CLICON_PLUGIN="example_cli";
|
||||||
|
|
||||||
|
# Translate variable "value" by incrementing its characters
|
||||||
|
translate value (<value:string translate:incstr()>),cli_set("/translate/value");
|
||||||
|
|
||||||
# Note, when switching to PT, change datamodel to only @datamodel
|
# Note, when switching to PT, change datamodel to only @datamodel
|
||||||
set @datamodel:example, cli_set();
|
set @datamodel:example, cli_set();
|
||||||
merge @datamodel:example, cli_merge();
|
merge @datamodel:example, cli_merge();
|
||||||
|
|
@ -21,7 +24,7 @@ debug("Debugging parts of the system"), cli_debug_cli((int32)1);{
|
||||||
}
|
}
|
||||||
copy("Copy and create a new object") {
|
copy("Copy and create a new object") {
|
||||||
interface("Copy interface"){
|
interface("Copy interface"){
|
||||||
<name:string expand_dbvar("candidate","/interfaces/interface=%s/name")>("name of interface to copy from") to("Copy to interface") <toname:string>("Name of interface to copy to"), cli_copy_config("candidate","//interface[%s=%s]","name","name","toname");
|
<name:string expand_dbvar("candidate","/interfaces/interface=%s/name")>("name of interface to copy from") to("Copy to interface") <toname:string>("Name of interface to copy to"), cli_copy_config("candidate","//interface[%s='%s']","name","name","toname");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
discard("Discard edits (rollback 0)"), discard_changes();
|
discard("Discard edits (rollback 0)"), discard_changes();
|
||||||
|
|
@ -36,11 +39,21 @@ show("Show a particular state of the system"){
|
||||||
text("Show comparison in text"), compare_dbs((int32)1);
|
text("Show comparison in text"), compare_dbs((int32)1);
|
||||||
}
|
}
|
||||||
configuration("Show configuration"), cli_show_config("candidate", "text", "/");{
|
configuration("Show configuration"), cli_show_config("candidate", "text", "/");{
|
||||||
xml("Show configuration as XML"), cli_show_config("candidate", "xml", "/");
|
xml("Show configuration as XML"), cli_show_config("candidate", "xml", "/");{
|
||||||
netconf("Show configuration as netconf edit-config operation"), cli_show_config("candidate", "netconf", "/");
|
@datamodel:example, cli_show_auto("candidate", "text");
|
||||||
text("Show configuration as text"), cli_show_config("candidate","text","/");
|
}
|
||||||
cli("Show configuration as cli commands"), cli_show_config("candidate", "cli", "/");
|
cli("Show configuration as CLI commands"), cli_show_config("candidate", "cli", "/");{
|
||||||
json("Show configuration as cli commands"), cli_show_config("candidate", "json", "/");
|
@datamodel:example, cli_show_auto("candidate", "cli");
|
||||||
|
}
|
||||||
|
netconf("Show configuration as netconf edit-config operation"), cli_show_config("candidate", "netconf", "/");{
|
||||||
|
@datamodel:example, cli_show_auto("candidate", "netconf");
|
||||||
|
}
|
||||||
|
text("Show configuration as text"), cli_show_config("candidate","text","/");{
|
||||||
|
@datamodel:example, cli_show_auto("candidate", "text");
|
||||||
|
}
|
||||||
|
json("Show configuration as JSON"), cli_show_config("candidate", "json", "/");{
|
||||||
|
@datamodel:example, cli_show_auto("candidate", "json");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -50,7 +63,7 @@ load("Load configuration from XML file") <filename:string>("Filename (local file
|
||||||
merge("Merge file with existent candidate"), load_config_file("filename", "merge");
|
merge("Merge file with existent candidate"), load_config_file("filename", "merge");
|
||||||
}
|
}
|
||||||
example("This is a comment") <var:int32>("Just a random number"), mycallback("myarg");
|
example("This is a comment") <var:int32>("Just a random number"), mycallback("myarg");
|
||||||
rpc("fib-route rpc") <instance:string>("routing instance"), fib_route_rpc("myarg");
|
rpc("ex:fib-route rpc") <instance:string>("routing instance"), fib_route_rpc("myarg");
|
||||||
notify("Get notifications from backend"), cli_notify("ROUTING", "1", "text");
|
notify("Get notifications from backend"), cli_notify("ROUTING", "1", "text");
|
||||||
no("Negate") notify("Get notifications from backend"), cli_notify("ROUTING", "0", "xml");
|
no("Negate") notify("Get notifications from backend"), cli_notify("ROUTING", "0", "xml");
|
||||||
lock,cli_lock("candidate");
|
lock,cli_lock("candidate");
|
||||||
|
|
|
||||||
1506
example/iana-if-type@2014-05-08.yang
Normal file
1506
example/iana-if-type@2014-05-08.yang
Normal file
File diff suppressed because it is too large
Load diff
13
example/systemd/example.service
Normal file
13
example/systemd/example.service
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
[Unit]
|
||||||
|
Description=Starts and stops a clixon example service on this system
|
||||||
|
Wants=example_restconf.service
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=forking
|
||||||
|
User=root
|
||||||
|
RestartSec=60
|
||||||
|
Restart=on-failure
|
||||||
|
ExecStart=/usr/local/sbin/clixon_backend -s running -f /usr/local/etc/example.xml
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
14
example/systemd/example_restconf.service
Normal file
14
example/systemd/example_restconf.service
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
[Unit]
|
||||||
|
Description=Starts and stops an example clixon restconf service on this system
|
||||||
|
Wants=example.service
|
||||||
|
After=example.service
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
User=www-data
|
||||||
|
WorkingDirectory=/www-data
|
||||||
|
Restart=on-failure
|
||||||
|
ExecStart=/www-data/clixon_restconf -f /usr/local/etc/example.xml
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
|
@ -1,142 +0,0 @@
|
||||||
/* include/clixon_config.h.in. Generated from configure.ac by autoheader. */
|
|
||||||
|
|
||||||
/* Clixon data dir for system yang files etc */
|
|
||||||
#undef CLIXON_DATADIR
|
|
||||||
|
|
||||||
/* Location for apps to find default config file */
|
|
||||||
#undef CLIXON_DEFAULT_CONFIG
|
|
||||||
|
|
||||||
/* Clixon major release */
|
|
||||||
#undef CLIXON_VERSION_MAJOR
|
|
||||||
|
|
||||||
/* Clixon minor release */
|
|
||||||
#undef CLIXON_VERSION_MINOR
|
|
||||||
|
|
||||||
/* Clixon path version */
|
|
||||||
#undef CLIXON_VERSION_PATCH
|
|
||||||
|
|
||||||
/* Clixon version string */
|
|
||||||
#undef CLIXON_VERSION_STRING
|
|
||||||
|
|
||||||
/* Define to 1 if you have the `alphasort' function. */
|
|
||||||
#undef HAVE_ALPHASORT
|
|
||||||
|
|
||||||
/* Define to 1 if you have the <cligen/cligen.h> header file. */
|
|
||||||
#undef HAVE_CLIGEN_CLIGEN_H
|
|
||||||
|
|
||||||
/* Define to 1 if you have the <crypt.h> header file. */
|
|
||||||
#undef HAVE_CRYPT_H
|
|
||||||
|
|
||||||
/* Define to 1 if you have the <depot.h> header file. */
|
|
||||||
#undef HAVE_DEPOT_H
|
|
||||||
|
|
||||||
/* Define to 1 if you have the `inet_aton' function. */
|
|
||||||
#undef HAVE_INET_ATON
|
|
||||||
|
|
||||||
/* Define to 1 if you have the <inttypes.h> header file. */
|
|
||||||
#undef HAVE_INTTYPES_H
|
|
||||||
|
|
||||||
/* Define to 1 if you have the `cligen' library (-lcligen). */
|
|
||||||
#undef HAVE_LIBCLIGEN
|
|
||||||
|
|
||||||
/* Define to 1 if you have the `crypt' library (-lcrypt). */
|
|
||||||
#undef HAVE_LIBCRYPT
|
|
||||||
|
|
||||||
/* Define to 1 if you have the `dl' library (-ldl). */
|
|
||||||
#undef HAVE_LIBDL
|
|
||||||
|
|
||||||
/* Define to 1 if you have the `fcgi' library (-lfcgi). */
|
|
||||||
#undef HAVE_LIBFCGI
|
|
||||||
|
|
||||||
/* Define to 1 if you have the `m' library (-lm). */
|
|
||||||
#undef HAVE_LIBM
|
|
||||||
|
|
||||||
/* Define to 1 if you have the `nsl' library (-lnsl). */
|
|
||||||
#undef HAVE_LIBNSL
|
|
||||||
|
|
||||||
/* Define to 1 if you have the `qdbm' library (-lqdbm). */
|
|
||||||
#undef HAVE_LIBQDBM
|
|
||||||
|
|
||||||
/* Define to 1 if you have the `socket' library (-lsocket). */
|
|
||||||
#undef HAVE_LIBSOCKET
|
|
||||||
|
|
||||||
/* Define to 1 if you have the <linux/if_vlan.h> header file. */
|
|
||||||
#undef HAVE_LINUX_IF_VLAN_H
|
|
||||||
|
|
||||||
/* Define to 1 if you have the <memory.h> header file. */
|
|
||||||
#undef HAVE_MEMORY_H
|
|
||||||
|
|
||||||
/* Define to 1 if you have the <qdbm/depot.h> header file. */
|
|
||||||
#undef HAVE_QDBM_DEPOT_H
|
|
||||||
|
|
||||||
/* Define to 1 if you have the `sigaction' function. */
|
|
||||||
#undef HAVE_SIGACTION
|
|
||||||
|
|
||||||
/* Define to 1 if you have the `sigvec' function. */
|
|
||||||
#undef HAVE_SIGVEC
|
|
||||||
|
|
||||||
/* Define to 1 if you have the <stdint.h> header file. */
|
|
||||||
#undef HAVE_STDINT_H
|
|
||||||
|
|
||||||
/* Define to 1 if you have the <stdlib.h> header file. */
|
|
||||||
#undef HAVE_STDLIB_H
|
|
||||||
|
|
||||||
/* Define to 1 if you have the <strings.h> header file. */
|
|
||||||
#undef HAVE_STRINGS_H
|
|
||||||
|
|
||||||
/* Define to 1 if you have the <string.h> header file. */
|
|
||||||
#undef HAVE_STRING_H
|
|
||||||
|
|
||||||
/* Define to 1 if you have the `strlcpy' function. */
|
|
||||||
#undef HAVE_STRLCPY
|
|
||||||
|
|
||||||
/* Define to 1 if you have the `strndup' function. */
|
|
||||||
#undef HAVE_STRNDUP
|
|
||||||
|
|
||||||
/* Define to 1 if you have the `strsep' function. */
|
|
||||||
#undef HAVE_STRSEP
|
|
||||||
|
|
||||||
/* Define to 1 if you have the `strverscmp' function. */
|
|
||||||
#undef HAVE_STRVERSCMP
|
|
||||||
|
|
||||||
/* Define to 1 if you have the <sys/stat.h> header file. */
|
|
||||||
#undef HAVE_SYS_STAT_H
|
|
||||||
|
|
||||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
|
||||||
#undef HAVE_SYS_TYPES_H
|
|
||||||
|
|
||||||
/* Define to 1 if you have the <sys/ucred.h> header file. */
|
|
||||||
#undef HAVE_SYS_UCRED_H
|
|
||||||
|
|
||||||
/* Define to 1 if you have the <unistd.h> header file. */
|
|
||||||
#undef HAVE_UNISTD_H
|
|
||||||
|
|
||||||
/* Define to 1 if you have the `versionsort' function. */
|
|
||||||
#undef HAVE_VERSIONSORT
|
|
||||||
|
|
||||||
/* Define to the address where bug reports for this package should be sent. */
|
|
||||||
#undef PACKAGE_BUGREPORT
|
|
||||||
|
|
||||||
/* Define to the full name of this package. */
|
|
||||||
#undef PACKAGE_NAME
|
|
||||||
|
|
||||||
/* Define to the full name and version of this package. */
|
|
||||||
#undef PACKAGE_STRING
|
|
||||||
|
|
||||||
/* Define to the one symbol short name of this package. */
|
|
||||||
#undef PACKAGE_TARNAME
|
|
||||||
|
|
||||||
/* Define to the home page for this package. */
|
|
||||||
#undef PACKAGE_URL
|
|
||||||
|
|
||||||
/* Define to the version of this package. */
|
|
||||||
#undef PACKAGE_VERSION
|
|
||||||
|
|
||||||
/* Define to 1 if you have the ANSI C header files. */
|
|
||||||
#undef STDC_HEADERS
|
|
||||||
|
|
||||||
/* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a
|
|
||||||
`char[]'. */
|
|
||||||
#undef YYTEXT_POINTER
|
|
||||||
|
|
||||||
#include <clixon_custom.h>
|
|
||||||
|
|
@ -1,134 +0,0 @@
|
||||||
/* include/clixon_config.h. Generated from clixon_config.h.in by configure. */
|
|
||||||
/* include/clixon_config.h.in. Generated from configure.ac by autoheader. */
|
|
||||||
|
|
||||||
/* Clixon major release */
|
|
||||||
#define CLIXON_VERSION_MAJOR 3
|
|
||||||
|
|
||||||
/* Clixon minor release */
|
|
||||||
#define CLIXON_VERSION_MINOR 3
|
|
||||||
|
|
||||||
/* Clixon path version */
|
|
||||||
#define CLIXON_VERSION_PATCH 2
|
|
||||||
|
|
||||||
/* Clixon version string */
|
|
||||||
#define CLIXON_VERSION_STRING "3.3.2"
|
|
||||||
|
|
||||||
/* Define to 1 if you have the `alphasort' function. */
|
|
||||||
#define HAVE_ALPHASORT 1
|
|
||||||
|
|
||||||
/* Define to 1 if you have the <cligen/cligen.h> header file. */
|
|
||||||
#define HAVE_CLIGEN_CLIGEN_H 1
|
|
||||||
|
|
||||||
/* Define to 1 if you have the <crypt.h> header file. */
|
|
||||||
#define HAVE_CRYPT_H 1
|
|
||||||
|
|
||||||
/* Define to 1 if you have the <depot.h> header file. */
|
|
||||||
/* #undef HAVE_DEPOT_H */
|
|
||||||
|
|
||||||
/* Define to 1 if you have the `inet_aton' function. */
|
|
||||||
#define HAVE_INET_ATON 1
|
|
||||||
|
|
||||||
/* Define to 1 if you have the <inttypes.h> header file. */
|
|
||||||
#define HAVE_INTTYPES_H 1
|
|
||||||
|
|
||||||
/* Define to 1 if you have the `crypt' library (-lcrypt). */
|
|
||||||
#define HAVE_LIBCRYPT 1
|
|
||||||
|
|
||||||
/* Define to 1 if you have the `dl' library (-ldl). */
|
|
||||||
#define HAVE_LIBDL 1
|
|
||||||
|
|
||||||
/* Define to 1 if you have the `fcgi' library (-lfcgi). */
|
|
||||||
#define HAVE_LIBFCGI 1
|
|
||||||
|
|
||||||
/* Define to 1 if you have the `m' library (-lm). */
|
|
||||||
#define HAVE_LIBM 1
|
|
||||||
|
|
||||||
/* Define to 1 if you have the `nsl' library (-lnsl). */
|
|
||||||
#define HAVE_LIBNSL 1
|
|
||||||
|
|
||||||
/* Define to 1 if you have the `qdbm' library (-lqdbm). */
|
|
||||||
#define HAVE_LIBQDBM 1
|
|
||||||
|
|
||||||
/* Define to 1 if you have the `socket' library (-lsocket). */
|
|
||||||
/* #undef HAVE_LIBSOCKET */
|
|
||||||
|
|
||||||
/* Define to 1 if you have the <linux/if_vlan.h> header file. */
|
|
||||||
#define HAVE_LINUX_IF_VLAN_H 1
|
|
||||||
|
|
||||||
/* Define to 1 if you have the <memory.h> header file. */
|
|
||||||
#define HAVE_MEMORY_H 1
|
|
||||||
|
|
||||||
/* Define to 1 if you have the <qdbm/depot.h> header file. */
|
|
||||||
#define HAVE_QDBM_DEPOT_H 1
|
|
||||||
|
|
||||||
/* Define to 1 if you have the `sigaction' function. */
|
|
||||||
#define HAVE_SIGACTION 1
|
|
||||||
|
|
||||||
/* Define to 1 if you have the `sigvec' function. */
|
|
||||||
#define HAVE_SIGVEC 1
|
|
||||||
|
|
||||||
/* Define to 1 if you have the <stdint.h> header file. */
|
|
||||||
#define HAVE_STDINT_H 1
|
|
||||||
|
|
||||||
/* Define to 1 if you have the <stdlib.h> header file. */
|
|
||||||
#define HAVE_STDLIB_H 1
|
|
||||||
|
|
||||||
/* Define to 1 if you have the <strings.h> header file. */
|
|
||||||
#define HAVE_STRINGS_H 1
|
|
||||||
|
|
||||||
/* Define to 1 if you have the <string.h> header file. */
|
|
||||||
#define HAVE_STRING_H 1
|
|
||||||
|
|
||||||
/* Define to 1 if you have the `strlcpy' function. */
|
|
||||||
/* #undef HAVE_STRLCPY */
|
|
||||||
|
|
||||||
/* Define to 1 if you have the `strndup' function. */
|
|
||||||
#define HAVE_STRNDUP 1
|
|
||||||
|
|
||||||
/* Define to 1 if you have the `strsep' function. */
|
|
||||||
#define HAVE_STRSEP 1
|
|
||||||
|
|
||||||
/* Define to 1 if you have the `strverscmp' function. */
|
|
||||||
#define HAVE_STRVERSCMP 1
|
|
||||||
|
|
||||||
/* Define to 1 if you have the <sys/stat.h> header file. */
|
|
||||||
#define HAVE_SYS_STAT_H 1
|
|
||||||
|
|
||||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
|
||||||
#define HAVE_SYS_TYPES_H 1
|
|
||||||
|
|
||||||
/* Define to 1 if you have the <sys/ucred.h> header file. */
|
|
||||||
/* #undef HAVE_SYS_UCRED_H */
|
|
||||||
|
|
||||||
/* Define to 1 if you have the <unistd.h> header file. */
|
|
||||||
#define HAVE_UNISTD_H 1
|
|
||||||
|
|
||||||
/* Define to 1 if you have the `versionsort' function. */
|
|
||||||
#define HAVE_VERSIONSORT 1
|
|
||||||
|
|
||||||
/* Define to the address where bug reports for this package should be sent. */
|
|
||||||
#define PACKAGE_BUGREPORT ""
|
|
||||||
|
|
||||||
/* Define to the full name of this package. */
|
|
||||||
#define PACKAGE_NAME ""
|
|
||||||
|
|
||||||
/* Define to the full name and version of this package. */
|
|
||||||
#define PACKAGE_STRING ""
|
|
||||||
|
|
||||||
/* Define to the one symbol short name of this package. */
|
|
||||||
#define PACKAGE_TARNAME ""
|
|
||||||
|
|
||||||
/* Define to the home page for this package. */
|
|
||||||
#define PACKAGE_URL ""
|
|
||||||
|
|
||||||
/* Define to the version of this package. */
|
|
||||||
#define PACKAGE_VERSION ""
|
|
||||||
|
|
||||||
/* Define to 1 if you have the ANSI C header files. */
|
|
||||||
#define STDC_HEADERS 1
|
|
||||||
|
|
||||||
/* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a
|
|
||||||
`char[]'. */
|
|
||||||
#define YYTEXT_POINTER 1
|
|
||||||
|
|
||||||
#include <clixon_custom.h>
|
|
||||||
|
|
@ -43,6 +43,26 @@
|
||||||
int strverscmp (__const char *__s1, __const char *__s2);
|
int strverscmp (__const char *__s1, __const char *__s2);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Set if you want to enable "v" cli callback functions, such as cli_setv()
|
||||||
|
* This was obsoleted in 3.7
|
||||||
|
*/
|
||||||
|
#undef COMPAT_CLIV
|
||||||
|
|
||||||
|
/* Set if you want to assert that all rpc messages have set username
|
||||||
|
*/
|
||||||
|
#undef RPC_USERNAME_ASSERT
|
||||||
|
|
||||||
|
/* Full xmlns validation check is made only if XML has associated YANG spec
|
||||||
|
*/
|
||||||
|
#define XMLNS_YANG_ONLY 1
|
||||||
|
|
||||||
|
/* Set if you want to enable old xpath functions in clixon_xsl.* instead of the
|
||||||
|
* the new xpath functions in clixon_xpath.*
|
||||||
|
* Note that when changing from old xpath code to new, calls on the form
|
||||||
|
* `x[a=str]` where `str` is a string (not a number or XML symbol),
|
||||||
|
* must be changed to: `x[a='str'] or x[a="str"]`
|
||||||
|
* Enabling COMPAT_XSL may make sense if you have written a lot of user code that
|
||||||
|
* relieson the error above. Or if a bug appears in the newimplementation.
|
||||||
|
* @see test/lib.sh
|
||||||
|
*/
|
||||||
|
#undef COMPAT_XSL
|
||||||
|
|
|
||||||
|
|
@ -82,6 +82,8 @@
|
||||||
#include <clixon/clixon_xml_map.h>
|
#include <clixon/clixon_xml_map.h>
|
||||||
#include <clixon/clixon_xml_db.h>
|
#include <clixon/clixon_xml_db.h>
|
||||||
#include <clixon/clixon_xsl.h>
|
#include <clixon/clixon_xsl.h>
|
||||||
|
#include <clixon/clixon_xpath_ctx.h>
|
||||||
|
#include <clixon/clixon_xpath.h>
|
||||||
#include <clixon/clixon_json.h>
|
#include <clixon/clixon_json.h>
|
||||||
#include <clixon/clixon_netconf_lib.h>
|
#include <clixon/clixon_netconf_lib.h>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -85,7 +85,11 @@ extern char clicon_err_reason[ERR_STRLEN];
|
||||||
* Prototypes
|
* Prototypes
|
||||||
*/
|
*/
|
||||||
int clicon_err_reset(void);
|
int clicon_err_reset(void);
|
||||||
|
#if defined(__GNUC__) && __GNUC__ >= 3
|
||||||
|
int clicon_err_fn(const char *fn, const int line, int level, int err, char *format, ...) __attribute__ ((format (printf, 5, 6)));
|
||||||
|
#else
|
||||||
int clicon_err_fn(const char *fn, const int line, int level, int err, char *format, ...);
|
int clicon_err_fn(const char *fn, const int line, int level, int err, char *format, ...);
|
||||||
|
#endif
|
||||||
char *clicon_strerror(int err);
|
char *clicon_strerror(int err);
|
||||||
void *clicon_err_save(void);
|
void *clicon_err_save(void);
|
||||||
int clicon_err_restore(void *handle);
|
int clicon_err_restore(void *handle);
|
||||||
|
|
|
||||||
|
|
@ -62,10 +62,16 @@ extern int debug;
|
||||||
int clicon_log_init(char *ident, int upto, int flags);
|
int clicon_log_init(char *ident, int upto, int flags);
|
||||||
int clicon_get_logflags(void);
|
int clicon_get_logflags(void);
|
||||||
int clicon_log_str(int level, char *msg);
|
int clicon_log_str(int level, char *msg);
|
||||||
|
#if defined(__GNUC__) && __GNUC__ >= 3
|
||||||
|
int clicon_log(int level, char *format, ...) __attribute__ ((format (printf, 2, 3)));
|
||||||
|
int clicon_debug(int dbglevel, char *format, ...) __attribute__ ((format (printf, 2, 3)));
|
||||||
|
#else
|
||||||
int clicon_log(int level, char *format, ...);
|
int clicon_log(int level, char *format, ...);
|
||||||
|
int clicon_debug(int dbglevel, char *format, ...);
|
||||||
|
#endif
|
||||||
clicon_log_notify_t *clicon_log_register_callback(clicon_log_notify_t *cb, void *arg);
|
clicon_log_notify_t *clicon_log_register_callback(clicon_log_notify_t *cb, void *arg);
|
||||||
int clicon_debug_init(int dbglevel, FILE *f);
|
int clicon_debug_init(int dbglevel, FILE *f);
|
||||||
int clicon_debug(int dbglevel, char *format, ...);
|
|
||||||
char *mon2name(int md);
|
char *mon2name(int md);
|
||||||
|
|
||||||
#endif /* _CLIXON_LOG_H_ */
|
#endif /* _CLIXON_LOG_H_ */
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,9 @@
|
||||||
/*
|
/*
|
||||||
* Constants
|
* Constants
|
||||||
*/
|
*/
|
||||||
/* Hardcoded plugin symbol. Must exist in all plugins to kickstart */
|
/* Hardcoded plugin symbol. Must exist in all plugins to kickstart
|
||||||
|
* @see clixon_plugin_init
|
||||||
|
*/
|
||||||
#define CLIXON_PLUGIN_INIT "clixon_plugin_init"
|
#define CLIXON_PLUGIN_INIT "clixon_plugin_init"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -91,8 +93,9 @@ typedef int (plgexit_t)(clicon_handle); /* Plugin exit */
|
||||||
/* Plugin authorization. Set username option (or not)
|
/* Plugin authorization. Set username option (or not)
|
||||||
* @param[in] Clicon handle
|
* @param[in] Clicon handle
|
||||||
* @param[in] void*, eg Fastcgihandle request restconf
|
* @param[in] void*, eg Fastcgihandle request restconf
|
||||||
* @retval 0 if credentials OK
|
* @retval -1 Fatal error
|
||||||
* @retval -1 credentials not OK
|
* @retval 0 Credential not OK
|
||||||
|
* @retval 1 Credential OK
|
||||||
*/
|
*/
|
||||||
typedef int (plgauth_t)(clicon_handle, void *);
|
typedef int (plgauth_t)(clicon_handle, void *);
|
||||||
|
|
||||||
|
|
@ -180,6 +183,7 @@ typedef struct clixon_plugin clixon_plugin;
|
||||||
/*! Plugin initialization function. Must appear in all plugins
|
/*! Plugin initialization function. Must appear in all plugins
|
||||||
* @param[in] h Clixon handle
|
* @param[in] h Clixon handle
|
||||||
* @retval api Pointer to API struct
|
* @retval api Pointer to API struct
|
||||||
|
* @retval NULL Failure (if clixon_err() called), module disabled otherwise.
|
||||||
* @see CLIXON_PLUGIN_INIT default symbol
|
* @see CLIXON_PLUGIN_INIT default symbol
|
||||||
*/
|
*/
|
||||||
clixon_plugin_api *clixon_plugin_init(clicon_handle h);
|
clixon_plugin_api *clixon_plugin_init(clicon_handle h);
|
||||||
|
|
|
||||||
|
|
@ -61,7 +61,11 @@ struct clicon_msg {
|
||||||
char *format_int2str(enum format_enum showas);
|
char *format_int2str(enum format_enum showas);
|
||||||
enum format_enum format_str2int(char *str);
|
enum format_enum format_str2int(char *str);
|
||||||
|
|
||||||
|
#if defined(__GNUC__) && __GNUC__ >= 3
|
||||||
|
struct clicon_msg *clicon_msg_encode(char *format, ...) __attribute__ ((format (printf, 1, 2)));
|
||||||
|
#else
|
||||||
struct clicon_msg *clicon_msg_encode(char *format, ...);
|
struct clicon_msg *clicon_msg_encode(char *format, ...);
|
||||||
|
#endif
|
||||||
int clicon_msg_decode(struct clicon_msg *msg, cxobj **xml);
|
int clicon_msg_decode(struct clicon_msg *msg, cxobj **xml);
|
||||||
|
|
||||||
int clicon_connect_unix(char *sockpath);
|
int clicon_connect_unix(char *sockpath);
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,8 @@ static const map_str2int atmap[] = {
|
||||||
{NULL, -1}
|
{NULL, -1}
|
||||||
};
|
};
|
||||||
* @endcode
|
* @endcode
|
||||||
|
* @see clicon_int2str
|
||||||
|
* @see clicon_str2int
|
||||||
*/
|
*/
|
||||||
struct map_str2int{
|
struct map_str2int{
|
||||||
char *ms_str;
|
char *ms_str;
|
||||||
|
|
|
||||||
|
|
@ -69,7 +69,7 @@ typedef struct xml cxobj; /* struct defined in clicon_xml.c */
|
||||||
* @retval 1 Abort, dont continue with others
|
* @retval 1 Abort, dont continue with others
|
||||||
* @retval 2 Locally, just abort this subtree, continue with others
|
* @retval 2 Locally, just abort this subtree, continue with others
|
||||||
*/
|
*/
|
||||||
typedef int (xml_applyfn_t)(cxobj *yn, void *arg);
|
typedef int (xml_applyfn_t)(cxobj *x, void *arg);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* xml_flag() flags:
|
* xml_flag() flags:
|
||||||
|
|
@ -80,6 +80,7 @@ typedef int (xml_applyfn_t)(cxobj *yn, void *arg);
|
||||||
#define XML_FLAG_CHANGE 0x08 /* Node is changed (commits) or child changed rec */
|
#define XML_FLAG_CHANGE 0x08 /* Node is changed (commits) or child changed rec */
|
||||||
#define XML_FLAG_NONE 0x10 /* Node is added as NONE */
|
#define XML_FLAG_NONE 0x10 /* Node is added as NONE */
|
||||||
|
|
||||||
|
|
||||||
/* Sort and binary search of XML children
|
/* Sort and binary search of XML children
|
||||||
* Experimental
|
* Experimental
|
||||||
*/
|
*/
|
||||||
|
|
@ -106,9 +107,6 @@ char *xml_value_append(cxobj *xn, char *val);
|
||||||
enum cxobj_type xml_type(cxobj *xn);
|
enum cxobj_type xml_type(cxobj *xn);
|
||||||
int xml_type_set(cxobj *xn, enum cxobj_type type);
|
int xml_type_set(cxobj *xn, enum cxobj_type type);
|
||||||
|
|
||||||
cg_var *xml_cv_get(cxobj *xn);
|
|
||||||
int xml_cv_set(cxobj *xn, cg_var *cv);
|
|
||||||
|
|
||||||
int xml_child_nr(cxobj *xn);
|
int xml_child_nr(cxobj *xn);
|
||||||
int xml_child_nr_type(cxobj *xn, enum cxobj_type type);
|
int xml_child_nr_type(cxobj *xn, enum cxobj_type type);
|
||||||
cxobj *xml_child_i(cxobj *xn, int i);
|
cxobj *xml_child_i(cxobj *xn, int i);
|
||||||
|
|
|
||||||
103
lib/clixon/clixon_xpath.h
Normal file
103
lib/clixon/clixon_xpath.h
Normal file
|
|
@ -0,0 +1,103 @@
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
***** BEGIN LICENSE BLOCK *****
|
||||||
|
|
||||||
|
Copyright (C) 2009-2018 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 *****
|
||||||
|
|
||||||
|
* Clixon XML XPATH 1.0 according to https://www.w3.org/TR/xpath-10
|
||||||
|
*/
|
||||||
|
#ifndef _CLIXON_XPATH_H
|
||||||
|
#define _CLIXON_XPATH_H
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Types
|
||||||
|
*/
|
||||||
|
enum xp_op{
|
||||||
|
XO_AND,
|
||||||
|
XO_OR,
|
||||||
|
XO_DIV,
|
||||||
|
XO_MOD,
|
||||||
|
XO_ADD,
|
||||||
|
XO_MULT,
|
||||||
|
XO_SUB,
|
||||||
|
XO_EQ,
|
||||||
|
XO_NE,
|
||||||
|
XO_GE,
|
||||||
|
XO_LE,
|
||||||
|
XO_LT,
|
||||||
|
XO_GT,
|
||||||
|
XO_UNION,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Axis specifiers according to https://www.w3.org/TR/xpath-10/#NT-AxisName */
|
||||||
|
enum axis_type{
|
||||||
|
A_NAN = 0, /* Not set */
|
||||||
|
A_ANCESTOR,
|
||||||
|
A_ANCESTOR_OR_SELF,
|
||||||
|
A_ATTRIBUTE,
|
||||||
|
A_CHILD,
|
||||||
|
A_DESCENDANT,
|
||||||
|
A_DESCENDANT_OR_SELF,
|
||||||
|
A_FOLLOWING,
|
||||||
|
A_FOLLOWING_SIBLING,
|
||||||
|
A_NAMESPACE,
|
||||||
|
A_PARENT,
|
||||||
|
A_PRECEEDING,
|
||||||
|
A_PRECEEDING_SIBLING,
|
||||||
|
A_SELF,
|
||||||
|
A_ROOT /* XXX Not in https://www.w3.org/TR/xpath-10 */
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Variables
|
||||||
|
*/
|
||||||
|
extern const map_str2int xpopmap[];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Prototypes
|
||||||
|
*/
|
||||||
|
#if defined(__GNUC__) && __GNUC__ >= 3
|
||||||
|
int xpath_vec(cxobj *xcur, char *format, cxobj ***vec, size_t *veclen, ...) __attribute__ ((format (printf, 2, 5)));
|
||||||
|
int xpath_vec_flag(cxobj *xcur, char *format, uint16_t flags,
|
||||||
|
cxobj ***vec, size_t *veclen, ...) __attribute__ ((format (printf, 2, 6)));
|
||||||
|
cxobj *xpath_first(cxobj *xcur, char *format, ...) __attribute__ ((format (printf, 2, 3)));
|
||||||
|
int xpath_vec_bool(cxobj *xcur, char *format, ...) __attribute__ ((format (printf, 2, 3)));
|
||||||
|
|
||||||
|
#else
|
||||||
|
int xpath_vec(cxobj *xcur, char *format, cxobj ***vec, size_t *veclen, ...);
|
||||||
|
int xpath_vec_flag(cxobj *xcur, char *format, uint16_t flags,
|
||||||
|
cxobj ***vec, size_t *veclen, ...);
|
||||||
|
cxobj *xpath_first(cxobj *xcur, char *format, ...);
|
||||||
|
int xpath_vec_bool(cxobj *xcur, char *format, ...);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
int xpath_vec_ctx(cxobj *xcur, char *xpath, xp_ctx **xrp);
|
||||||
|
|
||||||
|
#endif /* _CLIXON_XPATH_H */
|
||||||
103
lib/clixon/clixon_xpath_ctx.h
Normal file
103
lib/clixon/clixon_xpath_ctx.h
Normal file
|
|
@ -0,0 +1,103 @@
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
***** BEGIN LICENSE BLOCK *****
|
||||||
|
|
||||||
|
Copyright (C) 2009-2018 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 *****
|
||||||
|
|
||||||
|
* 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
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Types
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*! 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)
|
||||||
|
* number (a floating-point number)
|
||||||
|
* string (a sequence of UCS characters)
|
||||||
|
*/
|
||||||
|
enum xp_objtype{
|
||||||
|
XT_NODESET,
|
||||||
|
XT_BOOL,
|
||||||
|
XT_NUMBER,
|
||||||
|
XT_STRING
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Expression evaluation occurs with respect to a context. XSLT and XPointer specify how the context is
|
||||||
|
* determined for XPath expressions used in XSLT and XPointer respectively. The context consists of:
|
||||||
|
* a node (the context node)
|
||||||
|
* a pair of non-zero positive integers (the context position and the context size)
|
||||||
|
* a set of variable bindings
|
||||||
|
* a function library
|
||||||
|
* the set of namespace declarations in scope for the expression
|
||||||
|
|
||||||
|
* For each node in the node-set to be filtered, the PredicateExpr is
|
||||||
|
* evaluated with that node as the context node, with the number of nodes
|
||||||
|
* in the node-set as the context size, and with the proximity position
|
||||||
|
* of the node in the node-set with respect to the axis as the context
|
||||||
|
* position; if PredicateExpr evaluates to true for that node, the node
|
||||||
|
* is included in the new node-set; otherwise, it is not included.
|
||||||
|
*/
|
||||||
|
struct xp_ctx{
|
||||||
|
enum xp_objtype xc_type;
|
||||||
|
cxobj **xc_nodeset; /* if type XT_NODESET */
|
||||||
|
size_t xc_size; /* Length of nodeset */
|
||||||
|
int xc_bool; /* if xc_type XT_BOOL */
|
||||||
|
double xc_number; /* if xc_type XT_NUMBER */
|
||||||
|
char *xc_string; /* if xc_type XT_STRING */
|
||||||
|
cxobj *xc_node; /* Node in nodeset XXX maybe not needed*/
|
||||||
|
cxobj *xc_initial; /* RFC 7960 10.1.1 extension: for current() */
|
||||||
|
int xc_descendant; /* // */
|
||||||
|
/* NYI: a set of variable bindings, set of namespace declarations */
|
||||||
|
};
|
||||||
|
typedef struct xp_ctx xp_ctx;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Variables
|
||||||
|
*/
|
||||||
|
extern const map_str2int ctxmap[];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Prototypes
|
||||||
|
*/
|
||||||
|
int ctx_free(xp_ctx *xc);
|
||||||
|
xp_ctx *ctx_dup(xp_ctx *xc);
|
||||||
|
int ctx_nodeset_replace(xp_ctx *xc, cxobj **vec, size_t veclen);
|
||||||
|
int ctx_print(cbuf *cb, int id, xp_ctx *xc, char *str);
|
||||||
|
int ctx2boolean(xp_ctx *xc);
|
||||||
|
int ctx2string(xp_ctx *xc, char **str0);
|
||||||
|
int ctx2number(xp_ctx *xc, double *n0);
|
||||||
|
|
||||||
|
#endif /* _CLIXON_XPATH_CTX_H */
|
||||||
|
|
@ -39,10 +39,12 @@
|
||||||
/*
|
/*
|
||||||
* Prototypes
|
* Prototypes
|
||||||
*/
|
*/
|
||||||
cxobj *xpath_first(cxobj *cxtop, char *format, ...);
|
int xpath_vec_xsl(cxobj *cxtop, char *xpath, cxobj ***vec, size_t *veclen);
|
||||||
|
int xpath_vec_flag_xsl(cxobj *cxtop, char *xpath, uint16_t flags,
|
||||||
|
cxobj ***vec, size_t *veclen);
|
||||||
|
cxobj *xpath_first_xsl(cxobj *cxtop, char *xpath);
|
||||||
|
#ifdef COMPAT_XSL
|
||||||
cxobj *xpath_each(cxobj *xn_top, char *xpath, cxobj *prev);
|
cxobj *xpath_each(cxobj *xn_top, char *xpath, cxobj *prev);
|
||||||
int xpath_vec(cxobj *cxtop, char *format, cxobj ***vec, size_t *veclen, ...);
|
#endif
|
||||||
int xpath_vec_flag(cxobj *cxtop, char *xpath, uint16_t flags,
|
|
||||||
cxobj ***vec, size_t *veclen, ...);
|
|
||||||
|
|
||||||
#endif /* _CLIXON_XSL_H */
|
#endif /* _CLIXON_XSL_H */
|
||||||
|
|
|
||||||
|
|
@ -202,6 +202,7 @@ struct yang_stmt{
|
||||||
cvec *ys_cvec; /* List of stmt-specific variables
|
cvec *ys_cvec; /* List of stmt-specific variables
|
||||||
Y_RANGE: range_min, range_max
|
Y_RANGE: range_min, range_max
|
||||||
Y_LIST: vector of keys
|
Y_LIST: vector of keys
|
||||||
|
Y_TYPE & identity: store all derived types
|
||||||
*/
|
*/
|
||||||
yang_type_cache *ys_typecache; /* If ys_keyword==Y_TYPE, cache all typedef data except unions */
|
yang_type_cache *ys_typecache; /* If ys_keyword==Y_TYPE, cache all typedef data except unions */
|
||||||
};
|
};
|
||||||
|
|
@ -245,6 +246,7 @@ yang_stmt *yn_each(yang_node *yn, yang_stmt *ys);
|
||||||
char *yang_key2str(int keyword);
|
char *yang_key2str(int keyword);
|
||||||
char *yarg_prefix(yang_stmt *ys);
|
char *yarg_prefix(yang_stmt *ys);
|
||||||
char *yarg_id(yang_stmt *ys);
|
char *yarg_id(yang_stmt *ys);
|
||||||
|
int yang_nodeid_split(char *nodeid, char **prefix, char **id);
|
||||||
yang_stmt *ys_module(yang_stmt *ys);
|
yang_stmt *ys_module(yang_stmt *ys);
|
||||||
yang_spec *ys_spec(yang_stmt *ys);
|
yang_spec *ys_spec(yang_stmt *ys);
|
||||||
yang_stmt *yang_find_module_by_prefix(yang_stmt *ys, char *prefix);
|
yang_stmt *yang_find_module_by_prefix(yang_stmt *ys, char *prefix);
|
||||||
|
|
@ -252,9 +254,11 @@ yang_stmt *yang_find(yang_node *yn, int keyword, char *argument);
|
||||||
yang_stmt *yang_find_datanode(yang_node *yn, char *argument);
|
yang_stmt *yang_find_datanode(yang_node *yn, char *argument);
|
||||||
yang_stmt *yang_find_schemanode(yang_node *yn, char *argument);
|
yang_stmt *yang_find_schemanode(yang_node *yn, char *argument);
|
||||||
yang_stmt *yang_find_topnode(yang_spec *ysp, char *name, yang_class class);
|
yang_stmt *yang_find_topnode(yang_spec *ysp, char *name, yang_class class);
|
||||||
|
char *yang_find_myprefix(yang_stmt *ys);
|
||||||
int yang_order(yang_stmt *y);
|
int yang_order(yang_stmt *y);
|
||||||
int yang_print(FILE *f, yang_node *yn);
|
int yang_print(FILE *f, yang_node *yn);
|
||||||
int yang_print_cbuf(cbuf *cb, yang_node *yn, int marginal);
|
int yang_print_cbuf(cbuf *cb, yang_node *yn, int marginal);
|
||||||
|
yang_stmt *yang_parse_file(int fd, const char *name, yang_spec *ysp);
|
||||||
int yang_parse(clicon_handle h, const char *yang_dir,
|
int yang_parse(clicon_handle h, const char *yang_dir,
|
||||||
const char *module, const char *revision, yang_spec *ysp);
|
const char *module, const char *revision, yang_spec *ysp);
|
||||||
int yang_apply(yang_node *yn, enum rfc_6020 key, yang_applyfn_t fn,
|
int yang_apply(yang_node *yn, enum rfc_6020 key, yang_applyfn_t fn,
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,7 @@ sysconfdir = @sysconfdir@
|
||||||
HOST_VENDOR = @host_vendor@
|
HOST_VENDOR = @host_vendor@
|
||||||
|
|
||||||
SH_SUFFIX = @SH_SUFFIX@
|
SH_SUFFIX = @SH_SUFFIX@
|
||||||
|
|
||||||
CLIXON_VERSION = @CLIXON_VERSION@
|
CLIXON_VERSION = @CLIXON_VERSION@
|
||||||
CLIXON_MAJOR = @CLIXON_VERSION_MAJOR@
|
CLIXON_MAJOR = @CLIXON_VERSION_MAJOR@
|
||||||
CLIXON_MINOR = @CLIXON_VERSION_MINOR@
|
CLIXON_MINOR = @CLIXON_VERSION_MINOR@
|
||||||
|
|
@ -52,6 +53,8 @@ CLIXON_MINOR = @CLIXON_VERSION_MINOR@
|
||||||
VPATH = @srcdir@
|
VPATH = @srcdir@
|
||||||
CC = @CC@
|
CC = @CC@
|
||||||
CFLAGS = -fPIC @CFLAGS@
|
CFLAGS = -fPIC @CFLAGS@
|
||||||
|
INSTALL = @INSTALL@
|
||||||
|
INSTALL_LIB = @INSTALL@
|
||||||
INSTALLFLAGS = @INSTALLFLAGS@
|
INSTALLFLAGS = @INSTALLFLAGS@
|
||||||
LDFLAGS = @LDFLAGS@
|
LDFLAGS = @LDFLAGS@
|
||||||
LIBS = @LIBS@
|
LIBS = @LIBS@
|
||||||
|
|
@ -69,12 +72,13 @@ SRC = clixon_sig.c clixon_log.c clixon_err.c clixon_event.c \
|
||||||
clixon_json.c clixon_yang.c clixon_yang_type.c \
|
clixon_json.c clixon_yang.c clixon_yang_type.c \
|
||||||
clixon_hash.c clixon_options.c clixon_plugin.c \
|
clixon_hash.c clixon_options.c clixon_plugin.c \
|
||||||
clixon_proto.c clixon_proto_client.c \
|
clixon_proto.c clixon_proto_client.c \
|
||||||
clixon_xsl.c clixon_sha1.c clixon_xml_db.c clixon_netconf_lib.c
|
clixon_xsl.c clixon_xpath.c clixon_xpath_ctx.c clixon_sha1.c \
|
||||||
|
clixon_xml_db.c clixon_netconf_lib.c
|
||||||
|
|
||||||
YACCOBJS := lex.clixon_xml_parse.o clixon_xml_parse.tab.o \
|
YACCOBJS := lex.clixon_xml_parse.o clixon_xml_parse.tab.o \
|
||||||
lex.clixon_yang_parse.o clixon_yang_parse.tab.o \
|
lex.clixon_yang_parse.o clixon_yang_parse.tab.o \
|
||||||
lex.clixon_json_parse.o clixon_json_parse.tab.o
|
lex.clixon_json_parse.o clixon_json_parse.tab.o \
|
||||||
|
lex.clixon_xpath_parse.o clixon_xpath_parse.tab.o
|
||||||
|
|
||||||
# Generated src
|
# Generated src
|
||||||
GENSRC = build.c
|
GENSRC = build.c
|
||||||
|
|
@ -96,9 +100,11 @@ clean:
|
||||||
rm -f clixon_xml_parse.tab.[ch] clixon_xml_parse.yy.[co]
|
rm -f clixon_xml_parse.tab.[ch] clixon_xml_parse.yy.[co]
|
||||||
rm -f clixon_yang_parse.tab.[ch] clixon_yang_parse.[co]
|
rm -f clixon_yang_parse.tab.[ch] clixon_yang_parse.[co]
|
||||||
rm -f clixon_json_parse.tab.[ch] clixon_json_parse.[co]
|
rm -f clixon_json_parse.tab.[ch] clixon_json_parse.[co]
|
||||||
|
rm -f clixon_xpath_parse.tab.[ch] clixon_xpath_parse.[co]
|
||||||
rm -f lex.clixon_xml_parse.c
|
rm -f lex.clixon_xml_parse.c
|
||||||
rm -f lex.clixon_yang_parse.c
|
rm -f lex.clixon_yang_parse.c
|
||||||
rm -f lex.clixon_json_parse.c
|
rm -f lex.clixon_json_parse.c
|
||||||
|
rm -f lex.clixon_xpath_parse.c
|
||||||
|
|
||||||
#############################################################################
|
#############################################################################
|
||||||
# Implicit rules for lex and yacc.
|
# Implicit rules for lex and yacc.
|
||||||
|
|
@ -148,6 +154,18 @@ clixon_json_parse.tab.c clixon_json_parse.tab.h: clixon_json_parse.y
|
||||||
lex.clixon_json_parse.o : lex.clixon_json_parse.c clixon_json_parse.tab.h
|
lex.clixon_json_parse.o : lex.clixon_json_parse.c clixon_json_parse.tab.h
|
||||||
$(CC) $(INCLUDES) $(CPPFLAGS) $(CFLAGS) -Wno-error -c $<
|
$(CC) $(INCLUDES) $(CPPFLAGS) $(CFLAGS) -Wno-error -c $<
|
||||||
|
|
||||||
|
# xpath parser
|
||||||
|
lex.clixon_xpath_parse.c : clixon_xpath_parse.l clixon_xpath_parse.tab.h
|
||||||
|
$(LEX) -Pclixon_xpath_parse clixon_xpath_parse.l # -d is debug
|
||||||
|
|
||||||
|
clixon_xpath_parse.tab.c clixon_xpath_parse.tab.h: clixon_xpath_parse.y
|
||||||
|
$(YACC) -l -d -p clixon_xpath_parse clixon_xpath_parse.y # -t is debug
|
||||||
|
mv y.tab.c clixon_xpath_parse.tab.c
|
||||||
|
mv y.tab.h clixon_xpath_parse.tab.h
|
||||||
|
|
||||||
|
lex.clixon_xpath_parse.o : lex.clixon_xpath_parse.c clixon_xpath_parse.tab.h
|
||||||
|
$(CC) $(INCLUDES) $(CPPFLAGS) $(CFLAGS) -Wno-error -c $<
|
||||||
|
|
||||||
distclean: clean
|
distclean: clean
|
||||||
rm -f Makefile *~ .depend
|
rm -f Makefile *~ .depend
|
||||||
|
|
||||||
|
|
@ -162,7 +180,6 @@ build.c:
|
||||||
date +"const char CLIXON_BUILDSTR[64]=\"%Y.%m.%d %H:%M by `whoami` on `hostname`"\"\; > build.c;
|
date +"const char CLIXON_BUILDSTR[64]=\"%Y.%m.%d %H:%M by `whoami` on `hostname`"\"\; > build.c;
|
||||||
echo "const char CLIXON_VERSION[64]=\"$(CLIXON_VERSION)\""\; >> build.c;
|
echo "const char CLIXON_VERSION[64]=\"$(CLIXON_VERSION)\""\; >> build.c;
|
||||||
|
|
||||||
|
|
||||||
$(MYLIB) : $(GENOBJS) $(OBJS)
|
$(MYLIB) : $(GENOBJS) $(OBJS)
|
||||||
ifeq ($(HOST_VENDOR),apple)
|
ifeq ($(HOST_VENDOR),apple)
|
||||||
$(CC) $(LDFLAGS) -shared -o $@ $(GENOBJS) $(OBJS) $(LIBS) -undefined dynamic_lookup -o $@
|
$(CC) $(LDFLAGS) -shared -o $@ $(GENOBJS) $(OBJS) $(LIBS) -undefined dynamic_lookup -o $@
|
||||||
|
|
@ -182,8 +199,8 @@ install: install-lib
|
||||||
install-include:
|
install-include:
|
||||||
|
|
||||||
install-lib: $(MYLIB)
|
install-lib: $(MYLIB)
|
||||||
install -m 0755 -d $(DESTDIR)$(libdir)
|
$(INSTALL) -m 0755 -d $(DESTDIR)$(libdir)
|
||||||
install -m 0644 $(INSTALLFLAGS) $(MYLIB) $(DESTDIR)$(libdir)
|
$(INSTALL_LIB) -m 0644 $(INSTALLFLAGS) $(MYLIB) $(DESTDIR)$(libdir)
|
||||||
ln -sf $(MYLIB) $(DESTDIR)$(libdir)/$(MYLIBSO) # -l:libclixon.so.3
|
ln -sf $(MYLIB) $(DESTDIR)$(libdir)/$(MYLIBSO) # -l:libclixon.so.3
|
||||||
ln -sf $(MYLIBSO) $(DESTDIR)$(libdir)/$(MYLIBLINK) # -l:libclixon.so
|
ln -sf $(MYLIBSO) $(DESTDIR)$(libdir)/$(MYLIBLINK) # -l:libclixon.so
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -102,7 +102,8 @@ static struct errvec EV[] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
static char *
|
static char *
|
||||||
clicon_strerror1(int err, struct errvec vec[])
|
clicon_strerror1(int err,
|
||||||
|
struct errvec vec[])
|
||||||
{
|
{
|
||||||
struct errvec *ev;
|
struct errvec *ev;
|
||||||
|
|
||||||
|
|
@ -134,18 +135,18 @@ clicon_err_reset(void)
|
||||||
* - Set global reason string clicon_err_reason
|
* - Set global reason string clicon_err_reason
|
||||||
* @note: err direction (syslog and/or stderr) controlled by clicon_log_init()
|
* @note: err direction (syslog and/or stderr) controlled by clicon_log_init()
|
||||||
*
|
*
|
||||||
* @param fn Inline function name (when called from clicon_err() macro)
|
* @param[in] fn Inline function name (when called from clicon_err() macro)
|
||||||
* @param line Inline file line number (when called from clicon_err() macro)
|
* @param[in] line Inline file line number (when called from clicon_err() macro)
|
||||||
* @param err Error number, typically errno
|
* @param[in] err Error number, typically errno
|
||||||
* @param suberr Sub-error number
|
* @param[in] suberr Sub-error number
|
||||||
* @param reason Error string, format with argv
|
* @param[in] reason Error string, format with argv
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
clicon_err_fn(const char *fn,
|
clicon_err_fn(const char *fn,
|
||||||
const int line,
|
const int line,
|
||||||
int category,
|
int category,
|
||||||
int suberr,
|
int suberr,
|
||||||
char *reason, ...)
|
char *reason, ...)
|
||||||
{
|
{
|
||||||
va_list args;
|
va_list args;
|
||||||
int len;
|
int len;
|
||||||
|
|
|
||||||
|
|
@ -267,7 +267,7 @@ event_poll(int fd)
|
||||||
FD_ZERO(&fdset);
|
FD_ZERO(&fdset);
|
||||||
FD_SET(fd, &fdset);
|
FD_SET(fd, &fdset);
|
||||||
if ((retval = select(FD_SETSIZE, &fdset, NULL, NULL, &tnull)) < 0)
|
if ((retval = select(FD_SETSIZE, &fdset, NULL, NULL, &tnull)) < 0)
|
||||||
clicon_err(OE_EVENTS, errno, "%s select1: %s", __FUNCTION__, strerror(errno));
|
clicon_err(OE_EVENTS, errno, "select");
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -307,18 +307,17 @@ event_loop(void)
|
||||||
if (n == -1) {
|
if (n == -1) {
|
||||||
if (errno == EINTR){
|
if (errno == EINTR){
|
||||||
clicon_debug(1, "%s select: %s", __FUNCTION__, strerror(errno));
|
clicon_debug(1, "%s select: %s", __FUNCTION__, strerror(errno));
|
||||||
clicon_err(OE_EVENTS, errno, "%s select1: %s", __FUNCTION__, strerror(errno));
|
clicon_err(OE_EVENTS, errno, "select");
|
||||||
retval = 0;
|
retval = 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
clicon_err(OE_EVENTS, errno, "%s select2", __FUNCTION__);
|
clicon_err(OE_EVENTS, errno, "select");
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
if (n==0){ /* Timeout */
|
if (n==0){ /* Timeout */
|
||||||
e = ee_timers;
|
e = ee_timers;
|
||||||
ee_timers = ee_timers->e_next;
|
ee_timers = ee_timers->e_next;
|
||||||
clicon_debug(2, "%s timeout: %s[%x]",
|
clicon_debug(2, "%s timeout: %s", __FUNCTION__, e->e_string);
|
||||||
__FUNCTION__, e->e_string, e->e_arg);
|
|
||||||
if ((*e->e_fn)(0, e->e_arg) < 0){
|
if ((*e->e_fn)(0, e->e_arg) < 0){
|
||||||
free(e);
|
free(e);
|
||||||
goto err;
|
goto err;
|
||||||
|
|
@ -331,8 +330,7 @@ event_loop(void)
|
||||||
break;
|
break;
|
||||||
e_next = e->e_next;
|
e_next = e->e_next;
|
||||||
if(e->e_type == EVENT_FD && FD_ISSET(e->e_fd, &fdset)){
|
if(e->e_type == EVENT_FD && FD_ISSET(e->e_fd, &fdset)){
|
||||||
clicon_debug(2, "%s: FD_ISSET: %s[%x]",
|
clicon_debug(2, "%s: FD_ISSET: %s", __FUNCTION__, e->e_string);
|
||||||
__FUNCTION__, e->e_string, e->e_arg);
|
|
||||||
if ((*e->e_fn)(e->e_fd, e->e_arg) < 0){
|
if ((*e->e_fn)(e->e_fd, e->e_arg) < 0){
|
||||||
clicon_debug(1, "%s Error in: %s", __FUNCTION__, e->e_string);
|
clicon_debug(1, "%s Error in: %s", __FUNCTION__, e->e_string);
|
||||||
goto err;
|
goto err;
|
||||||
|
|
|
||||||
|
|
@ -241,12 +241,11 @@ group_name2gid(char *name,
|
||||||
gr = &g0;
|
gr = &g0;
|
||||||
/* This leaks memory in ubuntu */
|
/* This leaks memory in ubuntu */
|
||||||
if (getgrnam_r(name, gr, buf, sizeof(buf), >mp) < 0){
|
if (getgrnam_r(name, gr, buf, sizeof(buf), >mp) < 0){
|
||||||
clicon_err(OE_UNIX, errno, "%s: getgrnam_r(%s): %s",
|
clicon_err(OE_UNIX, errno, "getgrnam_r(%s)", name);
|
||||||
__FUNCTION__, name, strerror(errno));
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (gtmp == NULL){
|
if (gtmp == NULL){
|
||||||
clicon_err(OE_UNIX, 0, "%s: No such group: %s", __FUNCTION__, name);
|
clicon_err(OE_UNIX, 0, "No such group: %s", name);
|
||||||
fprintf(stderr, "No such group %s\n", name);
|
fprintf(stderr, "No such group %s\n", name);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -52,24 +52,24 @@
|
||||||
* clicon_hash_t *hash = hash_init();
|
* clicon_hash_t *hash = hash_init();
|
||||||
*
|
*
|
||||||
* n = 234;
|
* n = 234;
|
||||||
* hash_add (hash, "APA", &n, sizeof(n));
|
* hash_add(hash, "APA", &n, sizeof(n));
|
||||||
* hash_dump(hash, stdout);
|
* hash_dump(hash, stdout);
|
||||||
*
|
*
|
||||||
* puts("----");
|
* puts("----");
|
||||||
*
|
*
|
||||||
* hash_add (hash, "BEPA", "hoppla Polle!", strlen("hoppla Polle!")+1);
|
* hash_add(hash, "BEPA", "hoppla Polle!", strlen("hoppla Polle!")+1);
|
||||||
* puts((char *)hash_value(hash, "BEPA", NULL));
|
* puts((char *)hash_value(hash, "BEPA", NULL));
|
||||||
* hash_dump(hash, stdout);
|
* hash_dump(hash, stdout);
|
||||||
*
|
*
|
||||||
* puts("----");
|
* puts("----");
|
||||||
*
|
*
|
||||||
* n = 33;
|
* n = 33;
|
||||||
* hash_add (hash, "CEPA", &n, sizeof(n));
|
* hash_add(hash, "CEPA", &n, sizeof(n));
|
||||||
* hash_dump(hash, stdout);
|
* hash_dump(hash, stdout);
|
||||||
*
|
*
|
||||||
* puts("----");
|
* puts("----");
|
||||||
*
|
*
|
||||||
* hash_del (hash, "APA");
|
* hash_del(hash, "APA");
|
||||||
* hash_dump(hash, stdout);
|
* hash_dump(hash, stdout);
|
||||||
*
|
*
|
||||||
* hash_free(hash);
|
* hash_free(hash);
|
||||||
|
|
@ -118,11 +118,11 @@ hash_init (void)
|
||||||
{
|
{
|
||||||
clicon_hash_t *hash;
|
clicon_hash_t *hash;
|
||||||
|
|
||||||
if ((hash = (clicon_hash_t *)malloc (sizeof (clicon_hash_t) * HASH_SIZE)) == NULL){
|
if ((hash = (clicon_hash_t *)malloc(sizeof(clicon_hash_t) * HASH_SIZE)) == NULL){
|
||||||
clicon_err(OE_UNIX, errno, "malloc: %s", strerror(errno));
|
clicon_err(OE_UNIX, errno, "malloc: %s", strerror(errno));
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
memset (hash, 0, sizeof(clicon_hash_t)*HASH_SIZE);
|
memset(hash, 0, sizeof(clicon_hash_t)*HASH_SIZE);
|
||||||
return hash;
|
return hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -167,7 +167,7 @@ hash_lookup(clicon_hash_t *hash,
|
||||||
h = hash[bkt];
|
h = hash[bkt];
|
||||||
if (h) {
|
if (h) {
|
||||||
do {
|
do {
|
||||||
if (!strcmp (h->h_key, key))
|
if (!strcmp(h->h_key, key))
|
||||||
return h;
|
return h;
|
||||||
h = NEXTQ(clicon_hash_t, h);
|
h = NEXTQ(clicon_hash_t, h);
|
||||||
} while (h != hash[bkt]);
|
} while (h != hash[bkt]);
|
||||||
|
|
@ -218,15 +218,15 @@ hash_add(clicon_hash_t *hash,
|
||||||
clicon_hash_t new = NULL;
|
clicon_hash_t new = NULL;
|
||||||
|
|
||||||
/* If variable exist, don't allocate a new. just replace value */
|
/* If variable exist, don't allocate a new. just replace value */
|
||||||
h = hash_lookup (hash, key);
|
h = hash_lookup(hash, key);
|
||||||
if (h == NULL) {
|
if (h == NULL) {
|
||||||
if ((new = (clicon_hash_t)malloc (sizeof (*new))) == NULL){
|
if ((new = (clicon_hash_t)malloc(sizeof(*new))) == NULL){
|
||||||
clicon_err(OE_UNIX, errno, "malloc: %s", strerror(errno));
|
clicon_err(OE_UNIX, errno, "malloc: %s", strerror(errno));
|
||||||
goto catch;
|
goto catch;
|
||||||
}
|
}
|
||||||
memset (new, 0, sizeof (*new));
|
memset(new, 0, sizeof(*new));
|
||||||
|
|
||||||
new->h_key = strdup (key);
|
new->h_key = strdup(key);
|
||||||
if (new->h_key == NULL){
|
if (new->h_key == NULL){
|
||||||
clicon_err(OE_UNIX, errno, "strdup: %s", strerror(errno));
|
clicon_err(OE_UNIX, errno, "strdup: %s", strerror(errno));
|
||||||
goto catch;
|
goto catch;
|
||||||
|
|
@ -241,11 +241,11 @@ hash_add(clicon_hash_t *hash,
|
||||||
clicon_err(OE_UNIX, errno, "malloc: %s", strerror(errno));
|
clicon_err(OE_UNIX, errno, "malloc: %s", strerror(errno));
|
||||||
goto catch;
|
goto catch;
|
||||||
}
|
}
|
||||||
memcpy (newval, val, vlen);
|
memcpy(newval, val, vlen);
|
||||||
|
|
||||||
/* Free old value if existing variable */
|
/* Free old value if existing variable */
|
||||||
if (h->h_val)
|
if (h->h_val)
|
||||||
free (h->h_val);
|
free(h->h_val);
|
||||||
h->h_val = newval;
|
h->h_val = newval;
|
||||||
h->h_vlen = vlen;
|
h->h_vlen = vlen;
|
||||||
|
|
||||||
|
|
@ -258,8 +258,8 @@ hash_add(clicon_hash_t *hash,
|
||||||
catch:
|
catch:
|
||||||
if (new) {
|
if (new) {
|
||||||
if (new->h_key)
|
if (new->h_key)
|
||||||
free (new->h_key);
|
free(new->h_key);
|
||||||
free (new);
|
free(new);
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
@ -279,15 +279,15 @@ hash_del(clicon_hash_t *hash,
|
||||||
{
|
{
|
||||||
clicon_hash_t h;
|
clicon_hash_t h;
|
||||||
|
|
||||||
h = hash_lookup (hash, key);
|
h = hash_lookup(hash, key);
|
||||||
if (h == NULL)
|
if (h == NULL)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
DELQ(h, hash[hash_bucket(key)], clicon_hash_t);
|
DELQ(h, hash[hash_bucket(key)], clicon_hash_t);
|
||||||
|
|
||||||
free (h->h_key);
|
free(h->h_key);
|
||||||
free (h->h_val);
|
free(h->h_val);
|
||||||
free (h);
|
free(h);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -691,8 +691,9 @@ int
|
||||||
json_parse_str(char *str,
|
json_parse_str(char *str,
|
||||||
cxobj **xt)
|
cxobj **xt)
|
||||||
{
|
{
|
||||||
if ((*xt = xml_new("top", NULL, NULL)) == NULL)
|
if (*xt == NULL)
|
||||||
return -1;
|
if ((*xt = xml_new("top", NULL, NULL)) == NULL)
|
||||||
|
return -1;
|
||||||
return json_parse(str, "", *xt);
|
return json_parse(str, "", *xt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -729,16 +730,14 @@ json_parse_file(int fd,
|
||||||
int len = 0;
|
int len = 0;
|
||||||
|
|
||||||
if ((jsonbuf = malloc(jsonbuflen)) == NULL){
|
if ((jsonbuf = malloc(jsonbuflen)) == NULL){
|
||||||
clicon_err(OE_XML, errno, "%s: malloc", __FUNCTION__);
|
clicon_err(OE_XML, errno, "malloc");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
memset(jsonbuf, 0, jsonbuflen);
|
memset(jsonbuf, 0, jsonbuflen);
|
||||||
ptr = jsonbuf;
|
ptr = jsonbuf;
|
||||||
while (1){
|
while (1){
|
||||||
if ((ret = read(fd, &ch, 1)) < 0){
|
if ((ret = read(fd, &ch, 1)) < 0){
|
||||||
clicon_err(OE_XML, errno, "%s: read: [pid:%d]\n",
|
clicon_err(OE_XML, errno, "read");
|
||||||
__FUNCTION__,
|
|
||||||
(int)getpid());
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
|
|
@ -755,7 +754,7 @@ json_parse_file(int fd,
|
||||||
oldjsonbuflen = jsonbuflen;
|
oldjsonbuflen = jsonbuflen;
|
||||||
jsonbuflen *= 2;
|
jsonbuflen *= 2;
|
||||||
if ((jsonbuf = realloc(jsonbuf, jsonbuflen)) == NULL){
|
if ((jsonbuf = realloc(jsonbuf, jsonbuflen)) == NULL){
|
||||||
clicon_err(OE_XML, errno, "%s: realloc", __FUNCTION__);
|
clicon_err(OE_XML, errno, "realloc");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
memset(jsonbuf+oldjsonbuflen, 0, jsonbuflen-oldjsonbuflen);
|
memset(jsonbuf+oldjsonbuflen, 0, jsonbuflen-oldjsonbuflen);
|
||||||
|
|
@ -775,7 +774,7 @@ json_parse_file(int fd,
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Turn this on to get a json parse and pretty print test program
|
* Turn this on to get a json parse and pretty print test program
|
||||||
* Usage: xpath
|
* Usage: json
|
||||||
* read json from input
|
* read json from input
|
||||||
* Example compile:
|
* Example compile:
|
||||||
gcc -g -o json -I. -I../clixon ./clixon_json.c -lclixon -lcligen
|
gcc -g -o json -I. -I../clixon ./clixon_json.c -lclixon -lcligen
|
||||||
|
|
@ -792,7 +791,8 @@ usage(char *argv0)
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
main(int argc, char **argv)
|
main(int argc,
|
||||||
|
char **argv)
|
||||||
{
|
{
|
||||||
cxobj *xt;
|
cxobj *xt;
|
||||||
cxobj *xc;
|
cxobj *xc;
|
||||||
|
|
|
||||||
|
|
@ -101,7 +101,7 @@ object.
|
||||||
/* typecast macro */
|
/* typecast macro */
|
||||||
#define _JY ((struct clicon_json_yacc_arg *)_jy)
|
#define _JY ((struct clicon_json_yacc_arg *)_jy)
|
||||||
|
|
||||||
#define _YYERROR(msg) {clicon_debug(2, "YYERROR %s '%s' %d", (msg), clixon_json_parsetext, _JY->jy_linenum); YYERROR;}
|
#define _YYERROR(msg) {clicon_err(OE_XML, 0, "YYERROR %s '%s' %d", (msg), clixon_json_parsetext, _JY->jy_linenum); YYERROR;}
|
||||||
|
|
||||||
/* add _yy to error paramaters */
|
/* add _yy to error paramaters */
|
||||||
#define YY_(msgid) msgid
|
#define YY_(msgid) msgid
|
||||||
|
|
@ -139,7 +139,8 @@ extern int clixon_json_parseget_lineno (void);
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
clixon_json_parseerror(void *_jy, char *s)
|
clixon_json_parseerror(void *_jy,
|
||||||
|
char *s)
|
||||||
{
|
{
|
||||||
clicon_err(OE_XML, 0, "%s on line %d: %s at or before: '%s'",
|
clicon_err(OE_XML, 0, "%s on line %d: %s at or before: '%s'",
|
||||||
_JY->jy_name,
|
_JY->jy_name,
|
||||||
|
|
@ -192,7 +193,10 @@ json_current_clone(struct clicon_json_yacc_arg *jy)
|
||||||
{
|
{
|
||||||
cxobj *xn;
|
cxobj *xn;
|
||||||
|
|
||||||
assert(xn = jy->jy_current);
|
if (jy->jy_current == NULL){
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
xn = jy->jy_current;
|
||||||
json_current_pop(jy);
|
json_current_pop(jy);
|
||||||
if (jy->jy_current)
|
if (jy->jy_current)
|
||||||
json_current_new(jy, xml_name(xn));
|
json_current_new(jy, xml_name(xn));
|
||||||
|
|
@ -258,7 +262,7 @@ array : '[' ']'
|
||||||
;
|
;
|
||||||
|
|
||||||
valuelist : value
|
valuelist : value
|
||||||
| valuelist { json_current_clone(_JY);} ',' value
|
| valuelist { if (json_current_clone(_JY)< 0) _YYERROR("stack?");} ',' value
|
||||||
;
|
;
|
||||||
|
|
||||||
/* quoted string */
|
/* quoted string */
|
||||||
|
|
|
||||||
|
|
@ -157,13 +157,12 @@ slogtime(void)
|
||||||
|
|
||||||
|
|
||||||
/*! Make a logging call to syslog (or stderr).
|
/*! Make a logging call to syslog (or stderr).
|
||||||
*
|
|
||||||
* This is the _only_ place the actual syslog (or stderr) logging is made in clicon,..
|
|
||||||
* @note syslog makes itw own filtering, but if log to stderr we do it here
|
|
||||||
* @see clicon_debug()
|
|
||||||
*
|
*
|
||||||
* @param[in] level log level, eg LOG_DEBUG,LOG_INFO,...,LOG_EMERG. Thisis OR:d with facility == LOG_USER
|
* @param[in] level log level, eg LOG_DEBUG,LOG_INFO,...,LOG_EMERG. Thisis OR:d with facility == LOG_USER
|
||||||
* @param[in] msg Message to print as argv.
|
* @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 itw own filtering, but if log to stderr we do it here
|
||||||
|
* @see clicon_debug
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
clicon_log_str(int level,
|
clicon_log_str(int level,
|
||||||
|
|
@ -214,13 +213,13 @@ clicon_log_str(int level,
|
||||||
|
|
||||||
/*! Make a logging call to syslog using variable arg syntax.
|
/*! Make a logging call to syslog using variable arg syntax.
|
||||||
*
|
*
|
||||||
* See also clicon_log_init() and clicon_log_str()
|
* @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.
|
||||||
* @code
|
* @code
|
||||||
clicon_log(LOG_NOTICE, "%s: dump to dtd not supported", __PROGRAM__);
|
clicon_log(LOG_NOTICE, "%s: dump to dtd not supported", __PROGRAM__);
|
||||||
* @endcode
|
* @endcode
|
||||||
* @param[in] level log level, eg LOG_DEBUG,LOG_INFO,...,LOG_EMERG. Thisis OR:d with facility == LOG_USER
|
* @see cicon_log_init and clicon_log_str
|
||||||
* @param[in] format Message to print as argv.
|
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
clicon_log(int level,
|
clicon_log(int level,
|
||||||
|
|
|
||||||
|
|
@ -68,6 +68,8 @@
|
||||||
#include "clixon_xml.h"
|
#include "clixon_xml.h"
|
||||||
#include "clixon_plugin.h"
|
#include "clixon_plugin.h"
|
||||||
#include "clixon_xsl.h"
|
#include "clixon_xsl.h"
|
||||||
|
#include "clixon_xpath_ctx.h"
|
||||||
|
#include "clixon_xpath.h"
|
||||||
#include "clixon_xml_map.h"
|
#include "clixon_xml_map.h"
|
||||||
|
|
||||||
/* Mapping between Clicon startup modes string <--> constants,
|
/* Mapping between Clicon startup modes string <--> constants,
|
||||||
|
|
@ -148,7 +150,7 @@ clicon_option_readfile_xml(clicon_hash_t *copt,
|
||||||
clicon_err(OE_UNIX, errno, "configure file: %s", filename);
|
clicon_err(OE_UNIX, errno, "configure file: %s", filename);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
clicon_debug(2, "Reading config file %s", __FUNCTION__, filename);
|
clicon_debug(2, "%s: Reading config file %s", __FUNCTION__, filename);
|
||||||
fd = fileno(f);
|
fd = fileno(f);
|
||||||
if (xml_parse_file(fd, "</clicon>", yspec, &xt) < 0)
|
if (xml_parse_file(fd, "</clicon>", yspec, &xt) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -186,6 +188,7 @@ clicon_option_readfile_xml(clicon_hash_t *copt,
|
||||||
/*! Initialize option values
|
/*! Initialize option values
|
||||||
*
|
*
|
||||||
* Set default options, Read config-file, Check that all values are set.
|
* Set default options, Read config-file, Check that all values are set.
|
||||||
|
* Read clixon system config files
|
||||||
* @param[in] h clicon handle
|
* @param[in] h clicon handle
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
|
|
@ -289,10 +292,10 @@ clicon_option_str_set(clicon_handle h,
|
||||||
|
|
||||||
/*! Get options as integer but stored as string
|
/*! Get options as integer but stored as string
|
||||||
*
|
*
|
||||||
* @param h clicon handle
|
* @param[in] h clicon handle
|
||||||
* @param name name of option
|
* @param[in] name name of option
|
||||||
* @retval int An integer as aresult of atoi
|
* @retval int An integer as aresult of atoi
|
||||||
* @retval -1 If option does not exist
|
* @retval -1 If option does not exist
|
||||||
* @code
|
* @code
|
||||||
* if (clicon_option_exists(h, "X")
|
* if (clicon_option_exists(h, "X")
|
||||||
* return clicon_option_int(h, "X");
|
* return clicon_option_int(h, "X");
|
||||||
|
|
@ -330,10 +333,10 @@ clicon_option_int_set(clicon_handle h,
|
||||||
|
|
||||||
/*! Get options as bool but stored as string
|
/*! Get options as bool but stored as string
|
||||||
*
|
*
|
||||||
* @param h clicon handle
|
* @param[in] h clicon handle
|
||||||
* @param name name of option
|
* @param[in] name name of option
|
||||||
* @retval 0 false, or does not exist, or does not have a boolean value
|
* @retval 0 false, or does not exist, or does not have a boolean value
|
||||||
* @retval 1 true
|
* @retval 1 true
|
||||||
* @code
|
* @code
|
||||||
* if (clicon_option_exists(h, "X")
|
* if (clicon_option_exists(h, "X")
|
||||||
* return clicon_option_bool(h, "X");
|
* return clicon_option_bool(h, "X");
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,7 @@
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
|
#include <syslog.h>
|
||||||
|
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
|
|
@ -126,7 +127,7 @@ clixon_plugin_each_revert(clicon_handle h,
|
||||||
int nr)
|
int nr)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
clixon_plugin *cp;
|
clixon_plugin *cp = NULL;
|
||||||
clixon_plugin *cpnext = NULL;
|
clixon_plugin *cpnext = NULL;
|
||||||
|
|
||||||
if (cpprev == NULL)
|
if (cpprev == NULL)
|
||||||
|
|
@ -192,7 +193,7 @@ plugin_load_one(clicon_handle h,
|
||||||
dlerror(); /* Clear any existing error */
|
dlerror(); /* Clear any existing error */
|
||||||
if ((handle = dlopen(file, dlflags)) == NULL) {
|
if ((handle = dlopen(file, dlflags)) == NULL) {
|
||||||
error = (char*)dlerror();
|
error = (char*)dlerror();
|
||||||
clicon_err(OE_PLUGIN, errno, "dlopen: %s\n", error ? error : "Unknown error");
|
clicon_err(OE_PLUGIN, errno, "dlopen: %s", error ? error : "Unknown error");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
/* call plugin_init() if defined, eg CLIXON_PLUGIN_INIT or CLIXON_BACKEND_INIT */
|
/* call plugin_init() if defined, eg CLIXON_PLUGIN_INIT or CLIXON_BACKEND_INIT */
|
||||||
|
|
@ -204,12 +205,16 @@ plugin_load_one(clicon_handle h,
|
||||||
clicon_err(OE_UNIX, 0, "dlsym: %s: %s", file, error);
|
clicon_err(OE_UNIX, 0, "dlsym: %s: %s", file, error);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
clicon_err_reset();
|
||||||
if ((api = initfn(h)) == NULL) {
|
if ((api = initfn(h)) == NULL) {
|
||||||
clicon_err(OE_PLUGIN, errno, "Failed to initiate %s", strrchr(file,'/')?strchr(file, '/'):file);
|
if (!clicon_errno){ /* if clicon_err() is not called then log and continue */
|
||||||
if (!clicon_errno) /* sanity: log if clicon_err() is not called ! */
|
clicon_log(LOG_WARNING, "Warning: failed to initiate %s", strrchr(file,'/')?strchr(file, '/'):file);
|
||||||
clicon_err(OE_DB, 0, "Unknown error: %s: plugin_init does not make clicon_err call on error",
|
dlclose(handle);
|
||||||
file);
|
}
|
||||||
goto err;
|
else{
|
||||||
|
clicon_err(OE_PLUGIN, errno, "Failed to initiate %s", strrchr(file,'/')?strchr(file, '/'):file);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
/* Note: sizeof clixon_plugin_api which is largest of clixon_plugin_api:s */
|
/* Note: sizeof clixon_plugin_api which is largest of clixon_plugin_api:s */
|
||||||
if ((cp = (clixon_plugin *)malloc(sizeof(struct clixon_plugin))) == NULL){
|
if ((cp = (clixon_plugin *)malloc(sizeof(struct clixon_plugin))) == NULL){
|
||||||
|
|
@ -228,7 +233,8 @@ plugin_load_one(clicon_handle h,
|
||||||
|
|
||||||
snprintf(cp->cp_name, sizeof(cp->cp_name), "%*s",
|
snprintf(cp->cp_name, sizeof(cp->cp_name), "%*s",
|
||||||
(int)strlen(name), name);
|
(int)strlen(name), name);
|
||||||
cp->cp_api = *api;
|
if (api)
|
||||||
|
cp->cp_api = *api;
|
||||||
clicon_debug(1, "%s", __FUNCTION__);
|
clicon_debug(1, "%s", __FUNCTION__);
|
||||||
done:
|
done:
|
||||||
return cp;
|
return cp;
|
||||||
|
|
@ -342,7 +348,7 @@ clixon_plugin_exit(clicon_handle h)
|
||||||
}
|
}
|
||||||
if (dlclose(cp->cp_handle) != 0) {
|
if (dlclose(cp->cp_handle) != 0) {
|
||||||
error = (char*)dlerror();
|
error = (char*)dlerror();
|
||||||
clicon_err(OE_PLUGIN, errno, "dlclose: %s\n", error ? error : "Unknown error");
|
clicon_err(OE_PLUGIN, errno, "dlclose: %s", error ? error : "Unknown error");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (_clixon_plugins){
|
if (_clixon_plugins){
|
||||||
|
|
@ -430,7 +436,7 @@ rpc_callback_register(clicon_handle h,
|
||||||
clicon_err(OE_DB, errno, "malloc: %s", strerror(errno));
|
clicon_err(OE_DB, errno, "malloc: %s", strerror(errno));
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
memset (rc, 0, sizeof (*rc));
|
memset(rc, 0, sizeof(*rc));
|
||||||
rc->rc_callback = cb;
|
rc->rc_callback = cb;
|
||||||
rc->rc_arg = arg;
|
rc->rc_arg = arg;
|
||||||
rc->rc_tag = strdup(tag); /* XXX strdup memleak */
|
rc->rc_tag = strdup(tag); /* XXX strdup memleak */
|
||||||
|
|
@ -466,7 +472,7 @@ rpc_callback_delete_all(void)
|
||||||
* @param[in] h clicon handle
|
* @param[in] h clicon handle
|
||||||
* @param[in] xn Sub-tree (under xorig) at child of rpc: <rpc><xn></rpc>.
|
* @param[in] xn Sub-tree (under xorig) at child of rpc: <rpc><xn></rpc>.
|
||||||
* @param[out] xret Return XML, error or OK
|
* @param[out] xret Return XML, error or OK
|
||||||
* @param[in] arg Domain-speific arg (eg client_entry)
|
* @param[in] arg Domain-speific arg (eg client_entry)
|
||||||
*
|
*
|
||||||
* @retval -1 Error
|
* @retval -1 Error
|
||||||
* @retval 0 OK, not found handler.
|
* @retval 0 OK, not found handler.
|
||||||
|
|
|
||||||
|
|
@ -203,7 +203,7 @@ clicon_connect_unix(char *sockpath)
|
||||||
clicon_debug(2, "%s: connecting to %s", __FUNCTION__, addr.sun_path);
|
clicon_debug(2, "%s: connecting to %s", __FUNCTION__, addr.sun_path);
|
||||||
if (connect(s, (struct sockaddr *)&addr, SUN_LEN(&addr)) < 0){
|
if (connect(s, (struct sockaddr *)&addr, SUN_LEN(&addr)) < 0){
|
||||||
if (errno == EACCES)
|
if (errno == EACCES)
|
||||||
clicon_err(OE_CFG, errno, "connecting unix socket: %s.\n"
|
clicon_err(OE_CFG, errno, "connecting unix socket: %s."
|
||||||
"Client should be member of group $CLICON_SOCK_GROUP: ",
|
"Client should be member of group $CLICON_SOCK_GROUP: ",
|
||||||
sockpath);
|
sockpath);
|
||||||
else
|
else
|
||||||
|
|
@ -273,7 +273,7 @@ msg_dump(struct clicon_msg *msg)
|
||||||
for (i=0; i<ntohl(msg->op_len); i++){
|
for (i=0; i<ntohl(msg->op_len); i++){
|
||||||
snprintf(buf, sizeof(buf), "%s%02x", buf2, ((char*)msg)[i]&0xff);
|
snprintf(buf, sizeof(buf), "%s%02x", buf2, ((char*)msg)[i]&0xff);
|
||||||
if ((i+1)%32==0){
|
if ((i+1)%32==0){
|
||||||
clicon_debug(2, buf);
|
clicon_debug(2, "%s", buf);
|
||||||
snprintf(buf, sizeof(buf), "%s:", __FUNCTION__);
|
snprintf(buf, sizeof(buf), "%s:", __FUNCTION__);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -282,7 +282,7 @@ msg_dump(struct clicon_msg *msg)
|
||||||
strncpy(buf2, buf, sizeof(buf2));
|
strncpy(buf2, buf, sizeof(buf2));
|
||||||
}
|
}
|
||||||
if (i%32)
|
if (i%32)
|
||||||
clicon_debug(2, buf);
|
clicon_debug(2, "%s", buf);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -302,7 +302,7 @@ clicon_msg_send(int s,
|
||||||
msg_dump(msg);
|
msg_dump(msg);
|
||||||
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){
|
s, msg, ntohl(msg->op_len)) < 0){
|
||||||
clicon_err(OE_CFG, errno, "%s", __FUNCTION__);
|
clicon_err(OE_CFG, errno, "atomicio");
|
||||||
clicon_log(LOG_WARNING, "%s: write: %s len:%u msg:%s", __FUNCTION__,
|
clicon_log(LOG_WARNING, "%s: write: %s len:%u msg:%s", __FUNCTION__,
|
||||||
strerror(errno), ntohs(msg->op_len), msg->op_body);
|
strerror(errno), ntohs(msg->op_len), msg->op_body);
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -344,7 +344,7 @@ clicon_msg_rcv(int s,
|
||||||
set_signal(SIGINT, atomicio_sig_handler, &oldhandler);
|
set_signal(SIGINT, atomicio_sig_handler, &oldhandler);
|
||||||
|
|
||||||
if ((hlen = atomicio(read, s, &hdr, sizeof(hdr))) < 0){
|
if ((hlen = atomicio(read, s, &hdr, sizeof(hdr))) < 0){
|
||||||
clicon_err(OE_CFG, errno, "%s", __FUNCTION__);
|
clicon_err(OE_CFG, errno, "atomicio");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (hlen == 0){
|
if (hlen == 0){
|
||||||
|
|
@ -353,7 +353,7 @@ clicon_msg_rcv(int s,
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (hlen != sizeof(hdr)){
|
if (hlen != sizeof(hdr)){
|
||||||
clicon_err(OE_CFG, errno, "%s: header too short (%d)", __FUNCTION__, hlen);
|
clicon_err(OE_CFG, errno, "header too short (%d)", hlen);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
mlen = ntohl(hdr.op_len);
|
mlen = ntohl(hdr.op_len);
|
||||||
|
|
@ -365,11 +365,11 @@ clicon_msg_rcv(int s,
|
||||||
}
|
}
|
||||||
memcpy(*msg, &hdr, hlen);
|
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_CFG, errno, "%s: read", __FUNCTION__);
|
clicon_err(OE_CFG, errno, "read");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (len2 != mlen - sizeof(hdr)){
|
if (len2 != mlen - sizeof(hdr)){
|
||||||
clicon_err(OE_CFG, errno, "%s: body too short", __FUNCTION__);
|
clicon_err(OE_CFG, errno, "body too short");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (debug > 1)
|
if (debug > 1)
|
||||||
|
|
@ -504,7 +504,7 @@ clicon_rpc(int s,
|
||||||
if (clicon_msg_rcv(s, &reply, &eof) < 0)
|
if (clicon_msg_rcv(s, &reply, &eof) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (eof){
|
if (eof){
|
||||||
clicon_err(OE_PROTO, ESHUTDOWN, "%s: Socket unexpected close", __FUNCTION__);
|
clicon_err(OE_PROTO, ESHUTDOWN, "Socket unexpected close");
|
||||||
close(s);
|
close(s);
|
||||||
errno = ESHUTDOWN;
|
errno = ESHUTDOWN;
|
||||||
goto done;
|
goto done;
|
||||||
|
|
|
||||||
|
|
@ -65,6 +65,9 @@
|
||||||
#include "clixon_xml.h"
|
#include "clixon_xml.h"
|
||||||
#include "clixon_plugin.h"
|
#include "clixon_plugin.h"
|
||||||
#include "clixon_xsl.h"
|
#include "clixon_xsl.h"
|
||||||
|
#include "clixon_string.h"
|
||||||
|
#include "clixon_xpath_ctx.h"
|
||||||
|
#include "clixon_xpath.h"
|
||||||
#include "clixon_proto.h"
|
#include "clixon_proto.h"
|
||||||
#include "clixon_err.h"
|
#include "clixon_err.h"
|
||||||
#include "clixon_proto_client.h"
|
#include "clixon_proto_client.h"
|
||||||
|
|
@ -91,6 +94,9 @@ clicon_rpc_msg(clicon_handle h,
|
||||||
cxobj *xret = NULL;
|
cxobj *xret = NULL;
|
||||||
yang_spec *yspec;
|
yang_spec *yspec;
|
||||||
|
|
||||||
|
#ifdef RPC_USERNAME_ASSERT
|
||||||
|
assert(strstr(msg->op_body, "username")!=NULL); /* XXX */
|
||||||
|
#endif
|
||||||
clicon_debug(1, "%s request:%s", __FUNCTION__, msg->op_body);
|
clicon_debug(1, "%s request:%s", __FUNCTION__, msg->op_body);
|
||||||
if ((sock = clicon_sock(h)) == NULL){
|
if ((sock = clicon_sock(h)) == NULL){
|
||||||
clicon_err(OE_FATAL, 0, "CLICON_SOCK option not set");
|
clicon_err(OE_FATAL, 0, "CLICON_SOCK option not set");
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,6 @@
|
||||||
#include "clixon_string.h"
|
#include "clixon_string.h"
|
||||||
#include "clixon_err.h"
|
#include "clixon_err.h"
|
||||||
|
|
||||||
|
|
||||||
/*! Split string into a vector based on character delimiters. Using malloc
|
/*! Split string into a vector based on character delimiters. Using malloc
|
||||||
*
|
*
|
||||||
* The given string is split into a vector where the delimiter can be
|
* The given string is split into a vector where the delimiter can be
|
||||||
|
|
@ -63,6 +62,17 @@
|
||||||
* The vector returned is one single memory block that must be freed
|
* The vector returned is one single memory block that must be freed
|
||||||
* by the caller
|
* by the caller
|
||||||
*
|
*
|
||||||
|
* @code
|
||||||
|
* char **vec = NULL;
|
||||||
|
* int nvec;
|
||||||
|
* if ((vec = clicon_strsep("/home/user/src/clixon", "/", &nvec)) == NULL)
|
||||||
|
* err;
|
||||||
|
* for (i=0; i<nvec; i++){
|
||||||
|
* v = vec[i++];
|
||||||
|
* ...
|
||||||
|
* }
|
||||||
|
* free(vec);
|
||||||
|
* @endcode
|
||||||
* @param[in] string String to be split
|
* @param[in] string String to be split
|
||||||
* @param[in] delim String of delimiter characters
|
* @param[in] delim String of delimiter characters
|
||||||
* @param[out] nvec Number of entries in returned vector
|
* @param[out] nvec Number of entries in returned vector
|
||||||
|
|
@ -130,11 +140,11 @@ clicon_strjoin(int argc,
|
||||||
len += 1; /* '\0' */
|
len += 1; /* '\0' */
|
||||||
if ((str = malloc(len)) == NULL)
|
if ((str = malloc(len)) == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
memset (str, '\0', len);
|
memset(str, '\0', len);
|
||||||
for (i = 0; i < argc; i++) {
|
for (i = 0; i < argc; i++) {
|
||||||
if (i != 0)
|
if (i != 0)
|
||||||
strncat (str, delim, len - strlen(str));
|
strncat(str, delim, len - strlen(str));
|
||||||
strncat (str, argv[i], len - strlen(str));
|
strncat(str, argv[i], len - strlen(str));
|
||||||
}
|
}
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
@ -287,31 +297,56 @@ xml_chardata_encode(char *str,
|
||||||
int l;
|
int l;
|
||||||
int len;
|
int len;
|
||||||
int i, j;
|
int i, j;
|
||||||
|
int cdata; /* when set, skip encoding */
|
||||||
|
|
||||||
len = 0;
|
/* First compute length (do nothing) */
|
||||||
|
len = 0; cdata = 0;
|
||||||
for (i=0; i<strlen(str); i++){
|
for (i=0; i<strlen(str); i++){
|
||||||
switch (str[i]){
|
if (cdata){
|
||||||
case '&':
|
if (strncmp(&str[i], "]]>", strlen("]]>")) == 0)
|
||||||
len += strlen("& ");
|
cdata = 0;
|
||||||
break;
|
|
||||||
case '<':
|
|
||||||
len += strlen("< ");
|
|
||||||
break;
|
|
||||||
case '>':
|
|
||||||
len += strlen("> ");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
len++;
|
len++;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
switch (str[i]){
|
||||||
|
case '&':
|
||||||
|
len += strlen("& ");
|
||||||
|
break;
|
||||||
|
case '<':
|
||||||
|
if (strncmp(&str[i], "<![CDATA[", strlen("<![CDATA[")) == 0){
|
||||||
|
len++;
|
||||||
|
cdata++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
len += strlen("< ");
|
||||||
|
break;
|
||||||
|
case '>':
|
||||||
|
len += strlen("> ");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
len++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
len++; /* trailing \0 */
|
len++; /* trailing \0 */
|
||||||
|
/* We know length, allocate encoding buffer */
|
||||||
if ((esc = malloc(len)) == NULL){
|
if ((esc = malloc(len)) == NULL){
|
||||||
clicon_err(OE_UNIX, errno, "malloc");
|
clicon_err(OE_UNIX, errno, "malloc");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
memset(esc, 0, len);
|
memset(esc, 0, len);
|
||||||
j = 0;
|
|
||||||
|
/* Same code again, but now actually encode into output buffer */
|
||||||
|
j = 0; cdata = 0;
|
||||||
for (i=0; i<strlen(str); i++){
|
for (i=0; i<strlen(str); i++){
|
||||||
|
if (cdata){
|
||||||
|
if (strncmp(&str[i], "]]>", strlen("]]>")) == 0){
|
||||||
|
cdata = 0;
|
||||||
|
esc[j++] = str[i++];
|
||||||
|
esc[j++] = str[i++];
|
||||||
|
}
|
||||||
|
esc[j++] = str[i];
|
||||||
|
}
|
||||||
|
else
|
||||||
switch (str[i]){
|
switch (str[i]){
|
||||||
case '&':
|
case '&':
|
||||||
if ((l=snprintf(&esc[j], 7, "& ")) < 0){
|
if ((l=snprintf(&esc[j], 7, "& ")) < 0){
|
||||||
|
|
@ -321,6 +356,11 @@ xml_chardata_encode(char *str,
|
||||||
j += l;
|
j += l;
|
||||||
break;
|
break;
|
||||||
case '<':
|
case '<':
|
||||||
|
if (strncmp(&str[i], "<![CDATA[", strlen("<![CDATA[")) == 0){
|
||||||
|
esc[j++] = str[i];
|
||||||
|
cdata++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
if ((l=snprintf(&esc[j], 6, "< ")) < 0){
|
if ((l=snprintf(&esc[j], 6, "< ")) < 0){
|
||||||
clicon_err(OE_UNIX, errno, "snprintf");
|
clicon_err(OE_UNIX, errno, "snprintf");
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -478,21 +518,21 @@ clicon_str2int(const map_str2int *mstab,
|
||||||
*/
|
*/
|
||||||
#ifndef HAVE_STRNDUP
|
#ifndef HAVE_STRNDUP
|
||||||
char *
|
char *
|
||||||
clicon_strndup (const char *str,
|
clicon_strndup(const char *str,
|
||||||
size_t len)
|
size_t len)
|
||||||
{
|
{
|
||||||
char *new;
|
char *new;
|
||||||
size_t slen;
|
size_t slen;
|
||||||
|
|
||||||
slen = strlen (str);
|
slen = strlen(str);
|
||||||
len = (len < slen ? len : slen);
|
len = (len < slen ? len : slen);
|
||||||
|
|
||||||
new = malloc (len + 1);
|
new = malloc(len + 1);
|
||||||
if (new == NULL)
|
if (new == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
new[len] = '\0';
|
new[len] = '\0';
|
||||||
memcpy (new, str, len);
|
memcpy(new, str, len);
|
||||||
|
|
||||||
return new;
|
return new;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -109,10 +109,9 @@ struct xml{
|
||||||
enum cxobj_type x_type; /* type of node: element, attribute, body */
|
enum cxobj_type x_type; /* type of node: element, attribute, body */
|
||||||
char *x_value; /* attribute and body nodes have values */
|
char *x_value; /* attribute and body nodes have values */
|
||||||
int _x_vector_i; /* internal use: xml_child_each */
|
int _x_vector_i; /* internal use: xml_child_each */
|
||||||
int x_flags; /* Flags according to XML_FLAG_* above */
|
int x_flags; /* Flags according to XML_FLAG_* */
|
||||||
yang_stmt *x_spec; /* Pointer to specification, eg yang, by
|
yang_stmt *x_spec; /* Pointer to specification, eg yang, by
|
||||||
reference, dont free */
|
reference, dont free */
|
||||||
cg_var *x_cv; /* If body this contains the typed value */
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Mapping between xml type <--> string */
|
/* Mapping between xml type <--> string */
|
||||||
|
|
@ -181,7 +180,7 @@ xml_namespace(cxobj *xn)
|
||||||
return xn->x_namespace;
|
return xn->x_namespace;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Set name of xnode, name is copied
|
/*! Set name space of xnode, namespace is copied
|
||||||
* @param[in] xn xml node
|
* @param[in] xn xml node
|
||||||
* @param[in] namespace new namespace, null-terminated string, copied by function
|
* @param[in] namespace new namespace, null-terminated string, copied by function
|
||||||
* @retval -1 on error with clicon-err set
|
* @retval -1 on error with clicon-err set
|
||||||
|
|
@ -204,6 +203,74 @@ xml_namespace_set(cxobj *xn,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! See if xmlns:<namespace>=<uri> exists, if so return <uri>
|
||||||
|
*
|
||||||
|
* @param[in] xn XML node
|
||||||
|
* @param[in] nsn Namespace name
|
||||||
|
* @retval URI return associated URI if found
|
||||||
|
* @retval NULL No namespace name binding found for nsn
|
||||||
|
*/
|
||||||
|
static char *
|
||||||
|
xmlns_check(cxobj *xn,
|
||||||
|
char *nsn)
|
||||||
|
{
|
||||||
|
cxobj *x = NULL;
|
||||||
|
char *xns;
|
||||||
|
|
||||||
|
while ((x = xml_child_each(xn, x, -1)) != NULL)
|
||||||
|
if ((xns = xml_namespace(x)) && strcmp(xns, "xmlns")==0 &&
|
||||||
|
strcmp(xml_name(x), nsn) == 0)
|
||||||
|
return xml_value(x);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Check namespace of xml node by searhing recursively among ancestors
|
||||||
|
* @param[in] xn xml node
|
||||||
|
* @param[in] namespace check validity of namespace
|
||||||
|
* @retval 0 Found / validated or no yang spec
|
||||||
|
* @retval -1 Not found
|
||||||
|
* @note This function is grossly inefficient
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
xml_namespace_check(cxobj *xn,
|
||||||
|
void *arg)
|
||||||
|
{
|
||||||
|
cxobj *xp = NULL;
|
||||||
|
char *nsn;
|
||||||
|
char *n;
|
||||||
|
yang_stmt *ys = xml_spec(xn);
|
||||||
|
|
||||||
|
/* No namespace name - comply */
|
||||||
|
if ((nsn = xml_namespace(xn)) == NULL)
|
||||||
|
return 0;
|
||||||
|
/* Check if NSN defined in same node */
|
||||||
|
if (xmlns_check(xn, nsn) != NULL)
|
||||||
|
return 0;
|
||||||
|
/* Check if NSN defined in some ancestor */
|
||||||
|
while ((xp = xml_parent(xn)) != NULL) {
|
||||||
|
if (xmlns_check(xp, nsn) != NULL)
|
||||||
|
return 0;
|
||||||
|
xn = xp;
|
||||||
|
}
|
||||||
|
#ifdef XMLNS_YANG_ONLY
|
||||||
|
if (ys == NULL)
|
||||||
|
return 0; /* If no yang spec */
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
/* Check if my namespace */
|
||||||
|
if ((n = yang_find_myprefix(ys)) != NULL && strcmp(nsn,n)==0)
|
||||||
|
return 0;
|
||||||
|
/* Check if any imported module */
|
||||||
|
if (yang_find_module_by_prefix(ys, nsn) != NULL)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/* Not found, error */
|
||||||
|
clicon_err(OE_XML, ENOENT, "Namespace name %s in %s:%s not found",
|
||||||
|
nsn, nsn, xml_name(xn));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
/*! Get parent of xnode
|
/*! Get parent of xnode
|
||||||
* @param[in] xn xml node
|
* @param[in] xn xml node
|
||||||
* @retval parent xml node
|
* @retval parent xml node
|
||||||
|
|
@ -345,35 +412,6 @@ xml_type_set(cxobj *xn,
|
||||||
return old;
|
return old;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Get cligen variable associated with node
|
|
||||||
* @param[in] xn xml node
|
|
||||||
* @retval cv Cligen variable if set
|
|
||||||
* @retval NULL If not set, or not applicable
|
|
||||||
*/
|
|
||||||
cg_var *
|
|
||||||
xml_cv_get(cxobj *xn)
|
|
||||||
{
|
|
||||||
if (xn->x_cv)
|
|
||||||
return xn->x_cv;
|
|
||||||
else
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! Set cligen variable associated with node
|
|
||||||
* @param[in] xn xml node
|
|
||||||
* @param[in] cv Cligen variable or NULL
|
|
||||||
* @retval 0 if OK
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
xml_cv_set(cxobj *xn,
|
|
||||||
cg_var *cv)
|
|
||||||
{
|
|
||||||
if (xn->x_cv)
|
|
||||||
free(xn->x_cv);
|
|
||||||
xn->x_cv = cv;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! Get number of children
|
/*! Get number of children
|
||||||
* @param[in] xn xml node
|
* @param[in] xn xml node
|
||||||
* @retval number of children in XML tree
|
* @retval number of children in XML tree
|
||||||
|
|
@ -869,7 +907,6 @@ xml_find_value(cxobj *xt,
|
||||||
* Explaining picture:
|
* Explaining picture:
|
||||||
* xt --> x --> bx (x_type=CX_BODY)
|
* xt --> x --> bx (x_type=CX_BODY)
|
||||||
* x_name=name return x_value
|
* x_name=name return x_value
|
||||||
|
|
||||||
*/
|
*/
|
||||||
char *
|
char *
|
||||||
xml_find_body(cxobj *xt,
|
xml_find_body(cxobj *xt,
|
||||||
|
|
@ -932,8 +969,6 @@ xml_free(cxobj *x)
|
||||||
free(x->x_value);
|
free(x->x_value);
|
||||||
if (x->x_namespace)
|
if (x->x_namespace)
|
||||||
free(x->x_namespace);
|
free(x->x_namespace);
|
||||||
if (x->x_cv)
|
|
||||||
cv_free(x->x_cv);
|
|
||||||
for (i=0; i<x->x_childvec_len; i++){
|
for (i=0; i<x->x_childvec_len; i++){
|
||||||
if ((xc = x->x_childvec[i]) != NULL){
|
if ((xc = x->x_childvec[i]) != NULL){
|
||||||
xml_free(xc);
|
xml_free(xc);
|
||||||
|
|
@ -1247,6 +1282,9 @@ _xml_parse(const char *str,
|
||||||
goto done;
|
goto done;
|
||||||
if (clixon_xml_parseparse(&ya) != 0) /* yacc returns 1 on error */
|
if (clixon_xml_parseparse(&ya) != 0) /* yacc returns 1 on error */
|
||||||
goto done;
|
goto done;
|
||||||
|
/* Verify namespaces after parsing */
|
||||||
|
if (xml_apply0(xt, CX_ELMNT, xml_namespace_check, NULL) < 0)
|
||||||
|
goto done;
|
||||||
/* Sort the complete tree after parsing */
|
/* Sort the complete tree after parsing */
|
||||||
if (yspec){
|
if (yspec){
|
||||||
if (xml_apply0(xt, CX_ELMNT, xml_sort, NULL) < 0)
|
if (xml_apply0(xt, CX_ELMNT, xml_sort, NULL) < 0)
|
||||||
|
|
@ -1321,7 +1359,7 @@ xml_parse_file(int fd,
|
||||||
ptr = xmlbuf;
|
ptr = xmlbuf;
|
||||||
while (1){
|
while (1){
|
||||||
if ((ret = read(fd, &ch, 1)) < 0){
|
if ((ret = read(fd, &ch, 1)) < 0){
|
||||||
clicon_err(OE_XML, errno, "read: [pid:%d]\n",
|
clicon_err(OE_XML, errno, "read: [pid:%d]",
|
||||||
(int)getpid());
|
(int)getpid());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -1449,8 +1487,6 @@ int
|
||||||
xml_copy_one(cxobj *x0,
|
xml_copy_one(cxobj *x0,
|
||||||
cxobj *x1)
|
cxobj *x1)
|
||||||
{
|
{
|
||||||
cg_var *cv1;
|
|
||||||
|
|
||||||
xml_type_set(x1, xml_type(x0));
|
xml_type_set(x1, xml_type(x0));
|
||||||
if (xml_value(x0)){ /* malloced string */
|
if (xml_value(x0)){ /* malloced string */
|
||||||
if ((x1->x_value = strdup(x0->x_value)) == NULL){
|
if ((x1->x_value = strdup(x0->x_value)) == NULL){
|
||||||
|
|
@ -1461,14 +1497,6 @@ xml_copy_one(cxobj *x0,
|
||||||
if (xml_name(x0)) /* malloced string */
|
if (xml_name(x0)) /* malloced string */
|
||||||
if ((xml_name_set(x1, xml_name(x0))) < 0)
|
if ((xml_name_set(x1, xml_name(x0))) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
if (xml_cv_get(x0)){
|
|
||||||
if ((cv1 = cv_dup(xml_cv_get(x0))) == NULL){
|
|
||||||
clicon_err(OE_XML, errno, "cv_dup");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if ((xml_cv_set(x1, cv1)) < 0)
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1658,7 +1686,6 @@ xml_apply0(cxobj *xn,
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*! Apply a function call recursively on all ancestors
|
/*! Apply a function call recursively on all ancestors
|
||||||
* Recursively traverse upwards to all ancestor nodes in a parse-tree and apply fn(arg) for
|
* Recursively traverse upwards to all ancestor nodes in a parse-tree and apply fn(arg) for
|
||||||
* each object found. The function is called with the xml node and an
|
* each object found. The function is called with the xml node and an
|
||||||
|
|
@ -1737,7 +1764,7 @@ xml_body_parse(cxobj *xb,
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (cvret == 0){ /* parsing failed */
|
if (cvret == 0){ /* parsing failed */
|
||||||
clicon_err(OE_XML, errno, "Parsing CV: %s", &reason);
|
clicon_err(OE_XML, errno, "Parsing CV: %s", reason);
|
||||||
if (reason)
|
if (reason)
|
||||||
free(reason);
|
free(reason);
|
||||||
}
|
}
|
||||||
|
|
@ -1861,7 +1888,6 @@ xml_operation2str(enum operation_type op)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Turn this on to get a xml parse and pretty print test program
|
* Turn this on to get a xml parse and pretty print test program
|
||||||
* Usage: xpath
|
* Usage: xpath
|
||||||
|
|
@ -1871,7 +1897,7 @@ xml_operation2str(enum operation_type op)
|
||||||
* Example run:
|
* Example run:
|
||||||
echo "<a><b/></a>" | xml
|
echo "<a><b/></a>" | xml
|
||||||
*/
|
*/
|
||||||
#if 0 /* Test program */
|
#if 1 /* Test program */
|
||||||
|
|
||||||
static int
|
static int
|
||||||
usage(char *argv0)
|
usage(char *argv0)
|
||||||
|
|
@ -1883,7 +1909,7 @@ usage(char *argv0)
|
||||||
int
|
int
|
||||||
main(int argc, char **argv)
|
main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
cxobj *xt;
|
cxobj *xt = NULL;
|
||||||
cxobj *xc;
|
cxobj *xc;
|
||||||
cbuf *cb = cbuf_new();
|
cbuf *cb = cbuf_new();
|
||||||
|
|
||||||
|
|
@ -1891,8 +1917,8 @@ main(int argc, char **argv)
|
||||||
usage(argv[0]);
|
usage(argv[0]);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (xml_parse_file(0, "</config>", NULL,&xt) < 0){
|
if (xml_parse_file(0, "</config>", NULL, &xt) < 0){
|
||||||
fprintf(stderr, "parsing 2\n");
|
fprintf(stderr, "xml parse error %s\n", clicon_err_reason);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
xc = NULL;
|
xc = NULL;
|
||||||
|
|
|
||||||
|
|
@ -87,7 +87,7 @@ xmldb_plugin_load(clicon_handle h,
|
||||||
dlerror(); /* Clear any existing error */
|
dlerror(); /* Clear any existing error */
|
||||||
if ((handle = dlopen(filename, RTLD_NOW|RTLD_GLOBAL)) == NULL) {
|
if ((handle = dlopen(filename, RTLD_NOW|RTLD_GLOBAL)) == NULL) {
|
||||||
error = (char*)dlerror();
|
error = (char*)dlerror();
|
||||||
clicon_err(OE_PLUGIN, errno, "dlopen: %s\n", error ? error : "Unknown error");
|
clicon_err(OE_PLUGIN, errno, "dlopen: %s", error ? error : "Unknown error");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
/* Try v1 */
|
/* Try v1 */
|
||||||
|
|
@ -162,7 +162,7 @@ xmldb_plugin_unload(clicon_handle h)
|
||||||
dlerror(); /* Clear any existing error */
|
dlerror(); /* Clear any existing error */
|
||||||
if (dlclose(handle) != 0) {
|
if (dlclose(handle) != 0) {
|
||||||
error = (char*)dlerror();
|
error = (char*)dlerror();
|
||||||
clicon_err(OE_PLUGIN, errno, "dlclose: %s\n", error ? error : "Unknown error");
|
clicon_err(OE_PLUGIN, errno, "dlclose: %s", error ? error : "Unknown error");
|
||||||
/* Just report no -1 return*/
|
/* Just report no -1 return*/
|
||||||
}
|
}
|
||||||
retval = 0;
|
retval = 0;
|
||||||
|
|
|
||||||
|
|
@ -83,6 +83,8 @@
|
||||||
#include "clixon_options.h"
|
#include "clixon_options.h"
|
||||||
#include "clixon_xml.h"
|
#include "clixon_xml.h"
|
||||||
#include "clixon_plugin.h"
|
#include "clixon_plugin.h"
|
||||||
|
#include "clixon_xpath_ctx.h"
|
||||||
|
#include "clixon_xpath.h"
|
||||||
#include "clixon_xsl.h"
|
#include "clixon_xsl.h"
|
||||||
#include "clixon_log.h"
|
#include "clixon_log.h"
|
||||||
#include "clixon_err.h"
|
#include "clixon_err.h"
|
||||||
|
|
@ -226,7 +228,7 @@ xml2cli(FILE *f,
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Validate an xml node of type leafref, ensure the value is one of that path's reference
|
/*! 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] xt XML leaf node of type leafref
|
||||||
* @param[in] ytype Yang type statement belonging to the XML node
|
* @param[in] ytype Yang type statement belonging to the XML node
|
||||||
*/
|
*/
|
||||||
|
|
@ -249,7 +251,7 @@ validate_leafref(cxobj *xt,
|
||||||
clicon_err(OE_DB, 0, "Leafref %s requires path statement", ytype->ys_argument);
|
clicon_err(OE_DB, 0, "Leafref %s requires path statement", ytype->ys_argument);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (xpath_vec(xt, ypath->ys_argument, &xvec, &xlen) < 0)
|
if (xpath_vec(xt, "%s", &xvec, &xlen, ypath->ys_argument) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
for (i = 0; i < xlen; i++) {
|
for (i = 0; i < xlen; i++) {
|
||||||
x = xvec[i];
|
x = xvec[i];
|
||||||
|
|
@ -270,6 +272,72 @@ validate_leafref(cxobj *xt,
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! 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
|
||||||
|
* the identityref's base identities.
|
||||||
|
* Example:
|
||||||
|
* b0 --> b1 --> b2 (b1 & b2 are derived)
|
||||||
|
* identityref b2
|
||||||
|
* base b0;
|
||||||
|
* This function does: derived_from(b2, b0);
|
||||||
|
* @param[in] xt XML leaf node of type identityref
|
||||||
|
* @param[in] ys Yang spec of leaf
|
||||||
|
* @param[in] ytype Yang type field of type identityref
|
||||||
|
* @see ys_populate_identity where the derived types are set
|
||||||
|
* @see RFC7950 Sec 9.10.2:
|
||||||
|
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
validate_identityref(cxobj *xt,
|
||||||
|
yang_stmt *ys,
|
||||||
|
yang_stmt *ytype)
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
char *node;
|
||||||
|
yang_stmt *ybaseref; /* This is the type's base reference */
|
||||||
|
yang_stmt *ybaseid;
|
||||||
|
char *prefix = NULL;
|
||||||
|
cbuf *cb = NULL;
|
||||||
|
|
||||||
|
/* Get idref value. Then see if this value is derived from ytype.
|
||||||
|
* Always add default prefix because derived identifiers are stored with
|
||||||
|
* prefixes in the base identifiers derived-list.
|
||||||
|
*/
|
||||||
|
if ((node = xml_body(xt)) == NULL)
|
||||||
|
return 0;
|
||||||
|
if (strchr(node, ':') == NULL){
|
||||||
|
prefix = yang_find_myprefix(ys);
|
||||||
|
if ((cb = cbuf_new()) == NULL){
|
||||||
|
clicon_err(OE_UNIX, errno, "cbuf_new");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
cprintf(cb, "%s:%s", prefix, node);
|
||||||
|
node = cbuf_get(cb);
|
||||||
|
}
|
||||||
|
/* This is the type's base reference */
|
||||||
|
if ((ybaseref = yang_find((yang_node*)ytype, Y_BASE, NULL)) == NULL){
|
||||||
|
clicon_err(OE_DB, 0, "Identityref validation failed, no base");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
/* This is the actual base identity */
|
||||||
|
if ((ybaseid = yang_find_identity(ybaseref, ybaseref->ys_argument)) == NULL){
|
||||||
|
clicon_err(OE_DB, 0, "Identityref validation failed, no base identity");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
/* Here check if node is in the derived node list of the base identity */
|
||||||
|
if (cvec_find(ybaseid->ys_cvec, node) == NULL){
|
||||||
|
clicon_err(OE_DB, 0, "Identityref validation failed, %s not derived from %s", node, ybaseid->ys_argument);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
retval = 0;
|
||||||
|
done:
|
||||||
|
if (cb)
|
||||||
|
cbuf_free(cb);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
/*! Validate a single XML node with yang specification for added entry
|
/*! Validate a single XML node with yang specification for added entry
|
||||||
* 1. Check if mandatory leafs present as subs.
|
* 1. Check if mandatory leafs present as subs.
|
||||||
* 2. Check leaf values, eg int ranges and string regexps.
|
* 2. Check leaf values, eg int ranges and string regexps.
|
||||||
|
|
@ -360,28 +428,91 @@ xml_yang_validate_all(cxobj *xt,
|
||||||
void *arg)
|
void *arg)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
yang_stmt *ys;
|
yang_stmt *ys; /* yang node */
|
||||||
yang_stmt *ytype;
|
yang_stmt *yc; /* yang child */
|
||||||
|
yang_stmt *ye; /* yang must error-message */
|
||||||
|
char *xpath;
|
||||||
|
int nr;
|
||||||
|
|
||||||
/* if not given by argument (overide) use default link
|
/* if not given by argument (overide) use default link
|
||||||
and !Node has a config sub-statement and it is false */
|
and !Node has a config sub-statement and it is false */
|
||||||
if ((ys = xml_spec(xt)) != NULL &&
|
if ((ys = xml_spec(xt)) != NULL &&
|
||||||
yang_config(ys) != 0){
|
yang_config(ys) != 0){
|
||||||
|
/* Node-specific validation */
|
||||||
switch (ys->ys_keyword){
|
switch (ys->ys_keyword){
|
||||||
case Y_LEAF:
|
case Y_LEAF:
|
||||||
/* fall thru */
|
/* fall thru */
|
||||||
case Y_LEAF_LIST:
|
case Y_LEAF_LIST:
|
||||||
/* Special case if leaf is leafref, then first check against
|
/* Special case if leaf is leafref, then first check against
|
||||||
current xml tree
|
current xml tree
|
||||||
*/
|
*/
|
||||||
if ((ytype = yang_find((yang_node*)ys, Y_TYPE, NULL)) != NULL &&
|
if ((yc = yang_find((yang_node*)ys, Y_TYPE, NULL)) != NULL){
|
||||||
strcmp(ytype->ys_argument, "leafref") == 0)
|
if (strcmp(yc->ys_argument, "leafref") == 0){
|
||||||
if (validate_leafref(xt, ytype) < 0)
|
if (validate_leafref(xt, yc) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
}
|
||||||
|
else if (strcmp(yc->ys_argument, "identityref") == 0){
|
||||||
|
if (validate_identityref(xt, ys, yc) < 0)
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((yc = yang_find((yang_node*)ys, Y_MIN_ELEMENTS, NULL)) != NULL){
|
||||||
|
/* The behavior of the constraint depends on the type of the
|
||||||
|
* leaf-list's or list's closest ancestor node in the schema tree
|
||||||
|
* that is not a non-presence container (see Section 7.5.1):
|
||||||
|
* o If no such ancestor exists in the schema tree, the constraint
|
||||||
|
* is enforced.
|
||||||
|
* o Otherwise, if this ancestor is a case node, the constraint is
|
||||||
|
* enforced if any other node from the case exists.
|
||||||
|
* o Otherwise, it is enforced if the ancestor node exists.
|
||||||
|
*/
|
||||||
|
#if 0
|
||||||
|
cxobj *xp;
|
||||||
|
cxobj *x;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if ((xp = xml_parent(xt)) != NULL){
|
||||||
|
nr = atoi(yc->ys_argument);
|
||||||
|
x = NULL;
|
||||||
|
i = 0;
|
||||||
|
while ((x = xml_child_each(xt, x, CX_ELMNT)) != NULL)
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
if ((yc = yang_find((yang_node*)ys, Y_MAX_ELEMENTS, NULL)) != NULL){
|
||||||
|
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
/* must sub-node RFC 7950 Sec 7.5.3. Can be several. */
|
||||||
|
yc = NULL;
|
||||||
|
while ((yc = yn_each((yang_node*)ys, yc)) != NULL) {
|
||||||
|
if (yc->ys_keyword != Y_MUST)
|
||||||
|
continue;
|
||||||
|
xpath = yc->ys_argument; /* "must" has xpath argument */
|
||||||
|
if ((nr = xpath_vec_bool(xt, "%s", xpath)) < 0)
|
||||||
|
goto done;
|
||||||
|
if (!nr){
|
||||||
|
if ((ye = yang_find((yang_node*)yc, Y_ERROR_MESSAGE, NULL)) != NULL)
|
||||||
|
clicon_err(OE_DB, 0, "%s", ye->ys_argument);
|
||||||
|
else
|
||||||
|
clicon_err(OE_DB, 0, "xpath %s validation failed", xml_name(xt));
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* "when" sub-node RFC 7950 Sec 7.21.5. Can only be one. */
|
||||||
|
if ((yc = yang_find((yang_node*)ys, Y_WHEN, NULL)) != NULL){
|
||||||
|
xpath = yc->ys_argument; /* "when" has xpath argument */
|
||||||
|
if ((nr = xpath_vec_bool(xt, "%s", xpath)) < 0)
|
||||||
|
goto done;
|
||||||
|
if (!nr){
|
||||||
|
clicon_err(OE_DB, 0, "xpath %s validation failed", xml_name(xt));
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
|
|
@ -394,6 +525,7 @@ xml_yang_validate_all(cxobj *xt,
|
||||||
* @param[out] cvv CLIgen variable vector. Should be freed by cvec_free()
|
* @param[out] cvv CLIgen variable vector. Should be freed by cvec_free()
|
||||||
* @retval 0 Everything OK, cvv allocated and set
|
* @retval 0 Everything OK, cvv allocated and set
|
||||||
* @retval -1 Something wrong, clicon_err() called to set error. No cvv returned
|
* @retval -1 Something wrong, clicon_err() called to set error. No cvv returned
|
||||||
|
* @note cvv Should be freed by cvec_free() after use.
|
||||||
* 'Not recursive' means that only one level of XML bodies is translated to cvec:s.
|
* 'Not recursive' means that only one level of XML bodies is translated to cvec:s.
|
||||||
* If range is wriong (eg 1000 for uint8) a warning is logged, the value is
|
* If range is wriong (eg 1000 for uint8) a warning is logged, the value is
|
||||||
* skipped, and continues.
|
* skipped, and continues.
|
||||||
|
|
@ -426,7 +558,7 @@ xml2cvec(cxobj *xt,
|
||||||
char *name;
|
char *name;
|
||||||
|
|
||||||
xc = NULL;
|
xc = NULL;
|
||||||
/* Tried to allocate whole cvv here,but some cg_vars may be invalid */
|
/* Tried to allocate whole cvv here, but some cg_vars may be invalid */
|
||||||
if ((cvv = cvec_new(0)) == NULL){
|
if ((cvv = cvec_new(0)) == NULL){
|
||||||
clicon_err(OE_UNIX, errno, "cvec_new");
|
clicon_err(OE_UNIX, errno, "cvec_new");
|
||||||
goto err;
|
goto err;
|
||||||
|
|
@ -913,7 +1045,7 @@ api_path_fmt2api_path(char *api_path_fmt,
|
||||||
* @example
|
* @example
|
||||||
* api_path_fmt: /interface/%s/address/%s
|
* api_path_fmt: /interface/%s/address/%s
|
||||||
* cvv: name=eth0
|
* cvv: name=eth0
|
||||||
* xpath: /interface/[name=eth0]/address
|
* xpath: /interface/[name='eth0']/address
|
||||||
* @example
|
* @example
|
||||||
* api_path_fmt: /ip/me/%s (if key)
|
* api_path_fmt: /ip/me/%s (if key)
|
||||||
* cvv: -
|
* cvv: -
|
||||||
|
|
@ -956,7 +1088,13 @@ api_path_fmt2xpath(char *api_path_fmt,
|
||||||
clicon_err(OE_UNIX, errno, "cv2str_dup");
|
clicon_err(OE_UNIX, errno, "cv2str_dup");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
cprintf(cb, "[%s=%s]", cv_name_get(cv), str);
|
cprintf(cb,
|
||||||
|
#ifdef COMPAT_XSL
|
||||||
|
"[%s=%s]",
|
||||||
|
#else
|
||||||
|
"[%s='%s']",
|
||||||
|
#endif
|
||||||
|
cv_name_get(cv), str);
|
||||||
free(str);
|
free(str);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1301,7 +1439,6 @@ xml_spec_populate(cxobj *x,
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*! Translate from restconf api-path in cvv form to xml xpath
|
/*! Translate from restconf api-path in cvv form to xml xpath
|
||||||
* eg a/b=c -> a/[b=c]
|
* eg a/b=c -> a/[b=c]
|
||||||
* @param[in] yspec Yang spec
|
* @param[in] yspec Yang spec
|
||||||
|
|
@ -1374,7 +1511,13 @@ api_path2xpath_cvv(yang_spec *yspec,
|
||||||
cprintf(xpath, "/%s", name);
|
cprintf(xpath, "/%s", name);
|
||||||
v = val;
|
v = val;
|
||||||
while ((cvi = cvec_each(cvk, cvi)) != NULL){
|
while ((cvi = cvec_each(cvk, cvi)) != NULL){
|
||||||
cprintf(xpath, "[%s=%s]", cv_string_get(cvi), v);
|
cprintf(xpath,
|
||||||
|
#ifdef COMPAT_XSL
|
||||||
|
"[%s=%s]",
|
||||||
|
#else
|
||||||
|
"[%s='%s']",
|
||||||
|
#endif
|
||||||
|
cv_string_get(cvi), v);
|
||||||
v += strlen(v)+1;
|
v += strlen(v)+1;
|
||||||
}
|
}
|
||||||
if (val)
|
if (val)
|
||||||
|
|
@ -1644,6 +1787,7 @@ xml_merge1(cxobj *x0,
|
||||||
cxobj *x1c; /* mod child */
|
cxobj *x1c; /* mod child */
|
||||||
char *x1bstr; /* mod body string */
|
char *x1bstr; /* mod body string */
|
||||||
yang_stmt *yc; /* yang child */
|
yang_stmt *yc; /* yang child */
|
||||||
|
cbuf *cbr = NULL; /* Reason buffer */
|
||||||
|
|
||||||
assert(x1 && xml_type(x1) == CX_ELMNT);
|
assert(x1 && xml_type(x1) == CX_ELMNT);
|
||||||
assert(y0);
|
assert(y0);
|
||||||
|
|
@ -1682,9 +1826,16 @@ xml_merge1(cxobj *x0,
|
||||||
x1cname = xml_name(x1c);
|
x1cname = xml_name(x1c);
|
||||||
/* Get yang spec of the child */
|
/* Get yang spec of the child */
|
||||||
if ((yc = yang_find_datanode(y0, x1cname)) == NULL){
|
if ((yc = yang_find_datanode(y0, x1cname)) == NULL){
|
||||||
if (reason && (*reason = strdup("XML node has no corresponding yang specification (Invalid XML or wrong Yang spec?")) == NULL){
|
if (reason){
|
||||||
clicon_err(OE_UNIX, errno, "strdup");
|
if ((cbr = cbuf_new()) == NULL){
|
||||||
goto done;
|
clicon_err(OE_XML, errno, "cbuf_new");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
cprintf(cbr, "XML node %s/%s has no corresponding yang specification (Invalid XML or wrong Yang spec?", xml_name(x1), x1cname);
|
||||||
|
if ((*reason = strdup(cbuf_get(cbr))) == NULL){
|
||||||
|
clicon_err(OE_UNIX, errno, "strdup");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -1701,6 +1852,8 @@ xml_merge1(cxobj *x0,
|
||||||
ok:
|
ok:
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
|
if (cbr)
|
||||||
|
cbuf_free(cbr);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1708,7 +1861,7 @@ xml_merge1(cxobj *x0,
|
||||||
* @param[in] x0 Base xml tree (can be NULL in add scenarios)
|
* @param[in] x0 Base xml tree (can be NULL in add scenarios)
|
||||||
* @param[in] x1 xml tree which modifies base
|
* @param[in] x1 xml tree which modifies base
|
||||||
* @param[in] yspec Yang spec
|
* @param[in] yspec Yang spec
|
||||||
* @param[out] reason If retval=0 a malloced string. Needs to be freed by caller
|
* @param[out] reason If retval=0, reason is set. Malloced. Needs to be freed by caller
|
||||||
* @retval 0 OK. If reason is set, Yang error
|
* @retval 0 OK. If reason is set, Yang error
|
||||||
* @retval -1 Error
|
* @retval -1 Error
|
||||||
* @note both x0 and x1 need to be top-level trees
|
* @note both x0 and x1 need to be top-level trees
|
||||||
|
|
@ -1726,6 +1879,7 @@ xml_merge(cxobj *x0,
|
||||||
cxobj *x0c; /* base child */
|
cxobj *x0c; /* base child */
|
||||||
cxobj *x1c; /* mod child */
|
cxobj *x1c; /* mod child */
|
||||||
yang_stmt *yc;
|
yang_stmt *yc;
|
||||||
|
cbuf *cbr = NULL; /* Reason buffer */
|
||||||
|
|
||||||
/* Loop through children of the modification tree */
|
/* Loop through children of the modification tree */
|
||||||
x1c = NULL;
|
x1c = NULL;
|
||||||
|
|
@ -1733,9 +1887,16 @@ xml_merge(cxobj *x0,
|
||||||
x1cname = xml_name(x1c);
|
x1cname = xml_name(x1c);
|
||||||
/* Get yang spec of the child */
|
/* Get yang spec of the child */
|
||||||
if ((yc = yang_find_topnode(yspec, x1cname, YC_DATANODE)) == NULL){
|
if ((yc = yang_find_topnode(yspec, x1cname, YC_DATANODE)) == NULL){
|
||||||
if (reason && (*reason = strdup("XML node has no corresponding yang specification (Invalid XML or wrong Yang spec?")) == NULL){
|
if (reason){
|
||||||
clicon_err(OE_UNIX, errno, "strdup");
|
if ((cbr = cbuf_new()) == NULL){
|
||||||
goto done;
|
clicon_err(OE_XML, errno, "cbuf_new");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
cprintf(cbr, "XML node %s/%s has no corresponding yang specification (Invalid XML or wrong Yang spec?", xml_name(x1), x1cname);
|
||||||
|
if ((*reason = strdup(cbuf_get(cbr))) == NULL){
|
||||||
|
clicon_err(OE_UNIX, errno, "strdup");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -1749,6 +1910,8 @@ xml_merge(cxobj *x0,
|
||||||
}
|
}
|
||||||
retval = 0; /* OK */
|
retval = 0; /* OK */
|
||||||
done:
|
done:
|
||||||
|
if (cbr)
|
||||||
|
cbuf_free(cbr);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -77,6 +77,7 @@ int clixon_xml_parsewrap(void)
|
||||||
%x START
|
%x START
|
||||||
%s STATEA
|
%s STATEA
|
||||||
%s AMPERSAND
|
%s AMPERSAND
|
||||||
|
%s CDATA
|
||||||
%s CMNT
|
%s CMNT
|
||||||
%s STR
|
%s STR
|
||||||
%s TEXTDECL
|
%s TEXTDECL
|
||||||
|
|
@ -103,17 +104,23 @@ int clixon_xml_parsewrap(void)
|
||||||
|
|
||||||
<STATEA>"</" { BEGIN(START); return BSLASH; }
|
<STATEA>"</" { BEGIN(START); return BSLASH; }
|
||||||
<STATEA>"<!--" { BEGIN(CMNT); return BCOMMENT; }
|
<STATEA>"<!--" { BEGIN(CMNT); return BCOMMENT; }
|
||||||
|
<STATEA>"<![CDATA[" { BEGIN(CDATA); _YA->ya_lex_state = STATEA; clixon_xml_parselval.string = yytext; return CHARDATA;}
|
||||||
<STATEA>\< { BEGIN(START); return *clixon_xml_parsetext; }
|
<STATEA>\< { BEGIN(START); return *clixon_xml_parsetext; }
|
||||||
<STATEA>& { _YA->ya_lex_state =STATEA;BEGIN(AMPERSAND);}
|
<STATEA>& { _YA->ya_lex_state =STATEA;BEGIN(AMPERSAND);}
|
||||||
<STATEA>\n { clixon_xml_parselval.string = yytext;_YA->ya_linenum++; return (CHARDATA);}
|
<STATEA>\n { clixon_xml_parselval.string = yytext;_YA->ya_linenum++; return (CHARDATA);}
|
||||||
<STATEA>. { clixon_xml_parselval.string = yytext; return CHARDATA; /*XXX:optimize*/}
|
|
||||||
|
<STATEA>. { clixon_xml_parselval.string = yytext; return CHARDATA; /*XXX:optimize*/}
|
||||||
|
|
||||||
/* @see xml_chardata_encode */
|
/* @see xml_chardata_encode */
|
||||||
<AMPERSAND>"amp; " {BEGIN(_YA->ya_lex_state); clixon_xml_parselval.string = "&"; return CHARDATA;}
|
<AMPERSAND>"amp; " {BEGIN(_YA->ya_lex_state); clixon_xml_parselval.string = "&"; return CHARDATA;}
|
||||||
<AMPERSAND>"lt; " {BEGIN(_YA->ya_lex_state); clixon_xml_parselval.string = "<"; return CHARDATA;}
|
<AMPERSAND>"lt; " {BEGIN(_YA->ya_lex_state); clixon_xml_parselval.string = "<"; return CHARDATA;}
|
||||||
<AMPERSAND>"gt; " {BEGIN(_YA->ya_lex_state); clixon_xml_parselval.string = ">"; return CHARDATA;}
|
<AMPERSAND>"gt; " {BEGIN(_YA->ya_lex_state); clixon_xml_parselval.string = ">"; return CHARDATA;}
|
||||||
<AMPERSAND>"apos; " {BEGIN(_YA->ya_lex_state); clixon_xml_parselval.string = "'"; return CHARDATA;}
|
<AMPERSAND>"apos; " {BEGIN(_YA->ya_lex_state); clixon_xml_parselval.string = "'"; return CHARDATA;}
|
||||||
<AMPERSAND>"aquot; " {BEGIN(_YA->ya_lex_state); clixon_xml_parselval.string = "'"; return CHARDATA;}
|
<AMPERSAND>"quot; " {BEGIN(_YA->ya_lex_state); clixon_xml_parselval.string = "\""; return CHARDATA;}
|
||||||
|
|
||||||
|
<CDATA>. { clixon_xml_parselval.string = yytext; return CHARDATA;}
|
||||||
|
<CDATA>\n { clixon_xml_parselval.string = yytext;_YA->ya_linenum++; return (CHARDATA);}
|
||||||
|
<CDATA>"]]>" { BEGIN(_YA->ya_lex_state); clixon_xml_parselval.string = yytext; return CHARDATA;}
|
||||||
|
|
||||||
<CMNT>"-->" { BEGIN(START); return ECOMMENT; }
|
<CMNT>"-->" { BEGIN(START); return ECOMMENT; }
|
||||||
<CMNT>\n _YA->ya_linenum++;
|
<CMNT>\n _YA->ya_linenum++;
|
||||||
|
|
|
||||||
|
|
@ -47,8 +47,7 @@
|
||||||
%token BTEXT ETEXT
|
%token BTEXT ETEXT
|
||||||
%token BCOMMENT ECOMMENT
|
%token BCOMMENT ECOMMENT
|
||||||
|
|
||||||
|
%type <string> attvalue
|
||||||
%type <string> attvalue attqname
|
|
||||||
|
|
||||||
%lex-param {void *_ya} /* Add this argument to parse() and lex() function */
|
%lex-param {void *_ya} /* Add this argument to parse() and lex() function */
|
||||||
%parse-param {void *_ya}
|
%parse-param {void *_ya}
|
||||||
|
|
@ -117,7 +116,7 @@ xml_parse_version(struct xml_parse_yacc_arg *ya,
|
||||||
char *ver)
|
char *ver)
|
||||||
{
|
{
|
||||||
if(strcmp(ver, "1.0")){
|
if(strcmp(ver, "1.0")){
|
||||||
clicon_err(OE_XML, errno, "Wrong XML version %s expected 1.0\n", ver);
|
clicon_err(OE_XML, errno, "Wrong XML version %s expected 1.0", ver);
|
||||||
free(ver);
|
free(ver);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
@ -125,15 +124,41 @@ xml_parse_version(struct xml_parse_yacc_arg *ya,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Parse Qualified name
|
/*! Parse Qualified name --> Unprefixed name
|
||||||
* @param[in] ya XML parser yacc handler struct
|
* @param[in] ya XML parser yacc handler struct
|
||||||
* @param[in] prefix Prefix, namespace, or NULL
|
* @param[in] prefix Prefix, namespace, or NULL
|
||||||
* @param[in] localpart Name
|
* @param[in] localpart Name
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
xml_parse_qname(struct xml_parse_yacc_arg *ya,
|
xml_parse_unprefixed_name(struct xml_parse_yacc_arg *ya,
|
||||||
char *prefix,
|
char *name)
|
||||||
char *name)
|
{
|
||||||
|
int retval = -1;
|
||||||
|
cxobj *x;
|
||||||
|
yang_stmt *y = NULL; /* yang node */
|
||||||
|
cxobj *xp; /* xml parent */
|
||||||
|
|
||||||
|
xp = ya->ya_xparent;
|
||||||
|
if (xml_child_spec(name, xp, ya->ya_yspec, &y) < 0)
|
||||||
|
goto done;
|
||||||
|
if ((x = xml_new(name, xp, y)) == NULL)
|
||||||
|
goto done;
|
||||||
|
ya->ya_xelement = x;
|
||||||
|
retval = 0;
|
||||||
|
done:
|
||||||
|
free(name);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Parse Qualified name -> PrefixedName
|
||||||
|
* @param[in] ya XML parser yacc handler struct
|
||||||
|
* @param[in] prefix Prefix, namespace, or NULL
|
||||||
|
* @param[in] localpart Name
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
xml_parse_prefixed_name(struct xml_parse_yacc_arg *ya,
|
||||||
|
char *prefix,
|
||||||
|
char *name)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
cxobj *x;
|
cxobj *x;
|
||||||
|
|
@ -197,7 +222,7 @@ xml_parse_bslash1(struct xml_parse_yacc_arg *ya,
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (xml_namespace(x)!=NULL){
|
if (xml_namespace(x)!=NULL){
|
||||||
clicon_err(OE_XML, 0, "XML parse sanity check failed: %s:%s vs %s\n",
|
clicon_err(OE_XML, 0, "XML parse sanity check failed: %s:%s vs %s",
|
||||||
xml_namespace(x), xml_name(x), name);
|
xml_namespace(x), xml_name(x), name);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
@ -235,7 +260,7 @@ xml_parse_bslash2(struct xml_parse_yacc_arg *ya,
|
||||||
cxobj *xc;
|
cxobj *xc;
|
||||||
|
|
||||||
if (strcmp(xml_name(x), name)){
|
if (strcmp(xml_name(x), name)){
|
||||||
clicon_err(OE_XML, 0, "Sanity check failed: %s:%s vs %s:%s\n",
|
clicon_err(OE_XML, 0, "Sanity check failed: %s:%s vs %s:%s",
|
||||||
xml_namespace(x),
|
xml_namespace(x),
|
||||||
xml_name(x),
|
xml_name(x),
|
||||||
namespace,
|
namespace,
|
||||||
|
|
@ -244,7 +269,7 @@ xml_parse_bslash2(struct xml_parse_yacc_arg *ya,
|
||||||
}
|
}
|
||||||
if (xml_namespace(x)==NULL ||
|
if (xml_namespace(x)==NULL ||
|
||||||
strcmp(xml_namespace(x), namespace)){
|
strcmp(xml_namespace(x), namespace)){
|
||||||
clicon_err(OE_XML, 0, "Sanity check failed: %s:%s vs %s:%s\n",
|
clicon_err(OE_XML, 0, "Sanity check failed: %s:%s vs %s:%s",
|
||||||
xml_namespace(x),
|
xml_namespace(x),
|
||||||
xml_name(x),
|
xml_name(x),
|
||||||
namespace,
|
namespace,
|
||||||
|
|
@ -276,44 +301,29 @@ xml_parse_bslash2(struct xml_parse_yacc_arg *ya,
|
||||||
|
|
||||||
static int
|
static int
|
||||||
xml_parse_attr(struct xml_parse_yacc_arg *ya,
|
xml_parse_attr(struct xml_parse_yacc_arg *ya,
|
||||||
char *qname,
|
char *prefix,
|
||||||
|
char *name,
|
||||||
char *attval)
|
char *attval)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
cxobj *xa;
|
cxobj *xa;
|
||||||
|
|
||||||
if ((xa = xml_new(qname, ya->ya_xelement, NULL)) == NULL)
|
if ((xa = xml_new(name, ya->ya_xelement, NULL)) == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
xml_type_set(xa, CX_ATTR);
|
xml_type_set(xa, CX_ATTR);
|
||||||
|
if (prefix && xml_namespace_set(xa, prefix) < 0)
|
||||||
|
goto done;
|
||||||
if (xml_value_set(xa, attval) < 0)
|
if (xml_value_set(xa, attval) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
free(qname);
|
free(name);
|
||||||
|
if (prefix)
|
||||||
|
free(prefix);
|
||||||
free(attval);
|
free(attval);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Parse Attribue Qualified name, Just transform prefix:name into a new string
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
static char*
|
|
||||||
xml_merge_attqname(struct xml_parse_yacc_arg *ya,
|
|
||||||
char *prefix,
|
|
||||||
char *name)
|
|
||||||
{
|
|
||||||
char *str;
|
|
||||||
int len = strlen(prefix)+strlen(name)+2;
|
|
||||||
|
|
||||||
if ((str=malloc(len)) == NULL)
|
|
||||||
return NULL;
|
|
||||||
snprintf(str, len, "%s:%s", prefix, name);
|
|
||||||
free(prefix);
|
|
||||||
free(name);
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
%}
|
%}
|
||||||
|
|
||||||
%%
|
%%
|
||||||
|
|
@ -344,9 +354,9 @@ element : '<' qname attrs element1
|
||||||
{ clicon_debug(3, "element -> < qname attrs element1"); }
|
{ clicon_debug(3, "element -> < qname attrs element1"); }
|
||||||
;
|
;
|
||||||
|
|
||||||
qname : NAME { if (xml_parse_qname(_YA, NULL, $1) < 0) YYABORT;
|
qname : NAME { if (xml_parse_unprefixed_name(_YA, $1) < 0) YYABORT;
|
||||||
clicon_debug(3, "qname -> NAME %s", $1);}
|
clicon_debug(3, "qname -> NAME %s", $1);}
|
||||||
| NAME ':' NAME { if (xml_parse_qname(_YA, $1, $3) < 0) YYABORT;
|
| NAME ':' NAME { if (xml_parse_prefixed_name(_YA, $1, $3) < 0) YYABORT;
|
||||||
clicon_debug(3, "qname -> NAME : NAME");}
|
clicon_debug(3, "qname -> NAME : NAME");}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
@ -385,15 +395,10 @@ attrs : attrs attr
|
||||||
|
|
|
|
||||||
;
|
;
|
||||||
|
|
||||||
attr : attqname '=' attvalue { if (xml_parse_attr(_YA, $1, $3) < 0) YYABORT; }
|
attr : NAME '=' attvalue { if (xml_parse_attr(_YA, NULL, $1, $3) < 0) YYABORT; }
|
||||||
|
| NAME ':' NAME '=' attvalue { if (xml_parse_attr(_YA, $1, $3, $5) < 0) YYABORT; }
|
||||||
;
|
;
|
||||||
|
|
||||||
attqname : NAME {$$ = $1;}
|
|
||||||
| NAME ':' NAME
|
|
||||||
{ if (($$ = xml_merge_attqname(_YA, $1, $3)) == NULL) YYABORT; }
|
|
||||||
;
|
|
||||||
|
|
||||||
|
|
||||||
attvalue : '\"' CHARDATA '\"' { $$=$2; /* $2 must be consumed */}
|
attvalue : '\"' CHARDATA '\"' { $$=$2; /* $2 must be consumed */}
|
||||||
| '\"' '\"' { $$=strdup(""); /* $2 must be consumed */}
|
| '\"' '\"' { $$=strdup(""); /* $2 must be consumed */}
|
||||||
;
|
;
|
||||||
|
|
|
||||||
1364
lib/src/clixon_xpath.c
Normal file
1364
lib/src/clixon_xpath.c
Normal file
File diff suppressed because it is too large
Load diff
294
lib/src/clixon_xpath_ctx.c
Normal file
294
lib/src/clixon_xpath_ctx.c
Normal file
|
|
@ -0,0 +1,294 @@
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
***** BEGIN LICENSE BLOCK *****
|
||||||
|
|
||||||
|
Copyright (C) 2009-2018 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 *****
|
||||||
|
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <fnmatch.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <syslog.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
/* cligen */
|
||||||
|
#include <cligen/cligen.h>
|
||||||
|
|
||||||
|
/* clicon */
|
||||||
|
#include "clixon_err.h"
|
||||||
|
#include "clixon_log.h"
|
||||||
|
#include "clixon_string.h"
|
||||||
|
#include "clixon_queue.h"
|
||||||
|
#include "clixon_hash.h"
|
||||||
|
#include "clixon_handle.h"
|
||||||
|
#include "clixon_yang.h"
|
||||||
|
#include "clixon_xml.h"
|
||||||
|
#include "clixon_xpath_parse.h"
|
||||||
|
#include "clixon_xpath_ctx.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Variables
|
||||||
|
*/
|
||||||
|
const map_str2int ctxmap[] = {
|
||||||
|
{"nodeset", XT_NODESET},
|
||||||
|
{"bool", XT_BOOL},
|
||||||
|
{"number", XT_NUMBER},
|
||||||
|
{"string", XT_STRING},
|
||||||
|
{NULL, -1}
|
||||||
|
};
|
||||||
|
|
||||||
|
/*! Free xpath context */
|
||||||
|
int
|
||||||
|
ctx_free(xp_ctx *xc)
|
||||||
|
{
|
||||||
|
if (xc->xc_nodeset)
|
||||||
|
free(xc->xc_nodeset);
|
||||||
|
if (xc->xc_string)
|
||||||
|
free(xc->xc_string);
|
||||||
|
free(xc);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Duplicate xpath context */
|
||||||
|
xp_ctx *
|
||||||
|
ctx_dup(xp_ctx *xc0)
|
||||||
|
{
|
||||||
|
static xp_ctx *xc = NULL;
|
||||||
|
|
||||||
|
if ((xc = malloc(sizeof(*xc))) == NULL){
|
||||||
|
clicon_err(OE_UNIX, errno, "malloc");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
memset(xc, 0, sizeof(*xc));
|
||||||
|
*xc = *xc0;
|
||||||
|
if (xc0->xc_size){
|
||||||
|
if ((xc->xc_nodeset = calloc(xc0->xc_size, sizeof(cxobj*))) == NULL){
|
||||||
|
clicon_err(OE_UNIX, errno, "calloc");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
memcpy(xc->xc_nodeset, xc0->xc_nodeset, xc->xc_size*sizeof(cxobj*));
|
||||||
|
}
|
||||||
|
if (xc0->xc_string)
|
||||||
|
if ((xc->xc_string = strdup(xc0->xc_string)) == NULL){
|
||||||
|
clicon_err(OE_UNIX, errno, "strdup");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
done:
|
||||||
|
return xc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Print XPATH context */
|
||||||
|
int
|
||||||
|
ctx_print(cbuf *cb,
|
||||||
|
int id,
|
||||||
|
xp_ctx *xc,
|
||||||
|
char *str)
|
||||||
|
{
|
||||||
|
static int ident = 0;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (id<0)
|
||||||
|
ident += id;
|
||||||
|
cprintf(cb, "%*s%s ", ident, "", str?str:"");
|
||||||
|
if (id>0)
|
||||||
|
ident += id;
|
||||||
|
if (xc){
|
||||||
|
cprintf(cb, "%s: ", (char*)clicon_int2str(ctxmap, xc->xc_type));
|
||||||
|
switch (xc->xc_type){
|
||||||
|
case XT_NODESET:
|
||||||
|
for (i=0; i<xc->xc_size; i++)
|
||||||
|
cprintf(cb, "%s ", xml_name(xc->xc_nodeset[i]));
|
||||||
|
break;
|
||||||
|
case XT_BOOL:
|
||||||
|
cprintf(cb, "%s", xc->xc_bool?"true":"false");
|
||||||
|
break;
|
||||||
|
case XT_NUMBER:
|
||||||
|
cprintf(cb, "%lf", xc->xc_number);
|
||||||
|
break;
|
||||||
|
case XT_STRING:
|
||||||
|
cprintf(cb, "%s", xc->xc_string);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Convert xpath context to boolean according to boolean() function in XPATH spec
|
||||||
|
* @param[in] xc XPATH context
|
||||||
|
* @retval 0 False
|
||||||
|
* @retval 1 True
|
||||||
|
* 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
|
||||||
|
* an object of a type other than the four basic types is converted to a boolean
|
||||||
|
* in a way that is dependent on that type
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
ctx2boolean(xp_ctx *xc)
|
||||||
|
{
|
||||||
|
int b = -1;
|
||||||
|
switch (xc->xc_type){
|
||||||
|
case XT_NODESET:
|
||||||
|
b = (xc->xc_size != 0);
|
||||||
|
break;
|
||||||
|
case XT_BOOL:
|
||||||
|
b = xc->xc_bool;
|
||||||
|
break;
|
||||||
|
case XT_NUMBER:
|
||||||
|
b = (xc->xc_number != 0.0 && xc->xc_number != NAN);
|
||||||
|
break;
|
||||||
|
case XT_STRING:
|
||||||
|
b = (xc->xc_string && strlen(xc->xc_string));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! 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
|
||||||
|
* @note string malloced.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
ctx2string(xp_ctx *xc,
|
||||||
|
char **str0)
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
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]))){
|
||||||
|
if ((str = strdup(b)) == NULL){
|
||||||
|
clicon_err(OE_XML, errno, "strdup");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
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){
|
||||||
|
clicon_err(OE_XML, errno, "strdup");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case XT_NUMBER:
|
||||||
|
len = snprintf(NULL, 0, "%0lf", xc->xc_number);
|
||||||
|
len++;
|
||||||
|
if ((str = malloc(len)) == NULL){
|
||||||
|
clicon_err(OE_XML, errno, "malloc");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
snprintf(str, len, "%0lf", xc->xc_number);
|
||||||
|
break;
|
||||||
|
case XT_STRING:
|
||||||
|
if ((str = strdup(xc->xc_string)) == NULL){
|
||||||
|
clicon_err(OE_XML, errno, "strdup");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
*str0 = str;
|
||||||
|
retval = 0;
|
||||||
|
done:
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! 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
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
ctx2number(xp_ctx *xc,
|
||||||
|
double *n0)
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
char *str = NULL;
|
||||||
|
double n;
|
||||||
|
|
||||||
|
switch (xc->xc_type){
|
||||||
|
case XT_NODESET:
|
||||||
|
if (ctx2string(xc, &str) < 0)
|
||||||
|
goto done;
|
||||||
|
if (sscanf(str, "%lf",&n) != 1)
|
||||||
|
n = NAN;
|
||||||
|
break;
|
||||||
|
case XT_BOOL:
|
||||||
|
n = (double)xc->xc_bool;
|
||||||
|
break;
|
||||||
|
case XT_NUMBER:
|
||||||
|
n = xc->xc_number;
|
||||||
|
break;
|
||||||
|
case XT_STRING:
|
||||||
|
if (sscanf(xc->xc_string, "%lf",&n) != 1)
|
||||||
|
n = NAN;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
*n0 = n;
|
||||||
|
retval = 0;
|
||||||
|
done:
|
||||||
|
if (str)
|
||||||
|
free(str);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Replace a nodeset of a XPATH context with a new nodeset
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
ctx_nodeset_replace(xp_ctx *xc,
|
||||||
|
cxobj **vec,
|
||||||
|
size_t veclen)
|
||||||
|
{
|
||||||
|
if (xc->xc_nodeset)
|
||||||
|
free(xc->xc_nodeset);
|
||||||
|
xc->xc_nodeset = vec;
|
||||||
|
xc->xc_size = veclen;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
101
lib/src/clixon_xpath_parse.h
Normal file
101
lib/src/clixon_xpath_parse.h
Normal file
|
|
@ -0,0 +1,101 @@
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
***** BEGIN LICENSE BLOCK *****
|
||||||
|
|
||||||
|
Copyright (C) 2009-2018 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 *****
|
||||||
|
|
||||||
|
*/
|
||||||
|
#ifndef _CLIXON_XPATH_PARSE_H_
|
||||||
|
#define _CLIXON_XPATH_PARSE_H_
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Types
|
||||||
|
*/
|
||||||
|
/* used as non-terminal type in yacc rules */
|
||||||
|
enum xp_type{
|
||||||
|
XP_EXP,
|
||||||
|
XP_AND,
|
||||||
|
XP_RELEX,
|
||||||
|
XP_ADD,
|
||||||
|
XP_UNION,
|
||||||
|
XP_PATHEXPR,
|
||||||
|
XP_LOCPATH,
|
||||||
|
XP_ABSPATH,
|
||||||
|
XP_RELLOCPATH,
|
||||||
|
XP_STEP,
|
||||||
|
XP_NODE,
|
||||||
|
XP_NODE_FN,
|
||||||
|
XP_PRED,
|
||||||
|
XP_PRI0,
|
||||||
|
XP_PRIME_NR,
|
||||||
|
XP_PRIME_STR,
|
||||||
|
XP_PRIME_FN,
|
||||||
|
};
|
||||||
|
|
||||||
|
/*! XPATH Parsing generates a tree of nodes that is later traversed
|
||||||
|
*/
|
||||||
|
struct xpath_tree{
|
||||||
|
enum xp_type xs_type;
|
||||||
|
int xs_int;
|
||||||
|
double xs_double;
|
||||||
|
char *xs_s0;
|
||||||
|
char *xs_s1;
|
||||||
|
struct xpath_tree *xs_c0; /* child 0 */
|
||||||
|
struct xpath_tree *xs_c1; /* child 1 */
|
||||||
|
};
|
||||||
|
typedef struct xpath_tree xpath_tree;
|
||||||
|
|
||||||
|
struct clicon_xpath_yacc_arg{ /* XXX: mostly unrelevant */
|
||||||
|
const char *xy_name; /* Name of syntax (for error string) */
|
||||||
|
int xy_linenum; /* Number of \n in parsed buffer */
|
||||||
|
char *xy_parse_string; /* original (copy of) parse string */
|
||||||
|
void *xy_lexbuf; /* internal parse buffer from lex */
|
||||||
|
xpath_tree *xy_top;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Variables
|
||||||
|
*/
|
||||||
|
extern char *clixon_xpath_parsetext;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Prototypes
|
||||||
|
*/
|
||||||
|
int xpath_scan_init(struct clicon_xpath_yacc_arg *jy);
|
||||||
|
int xpath_scan_exit(struct clicon_xpath_yacc_arg *jy);
|
||||||
|
|
||||||
|
int xpath_parse_init(struct clicon_xpath_yacc_arg *jy);
|
||||||
|
int xpath_parse_exit(struct clicon_xpath_yacc_arg *jy);
|
||||||
|
|
||||||
|
int clixon_xpath_parselex(void *);
|
||||||
|
int clixon_xpath_parseparse(void *);
|
||||||
|
void clixon_xpath_parseerror(void *, char*);
|
||||||
|
|
||||||
|
#endif /* _CLIXON_XPATH_PARSE_H_ */
|
||||||
174
lib/src/clixon_xpath_parse.l
Normal file
174
lib/src/clixon_xpath_parse.l
Normal file
|
|
@ -0,0 +1,174 @@
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
***** BEGIN LICENSE BLOCK *****
|
||||||
|
|
||||||
|
Copyright (C) 2009-2018 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 *****
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
%{
|
||||||
|
|
||||||
|
#include "clixon_config.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
|
||||||
|
#include "clixon_xpath_parse.tab.h" /* generated */
|
||||||
|
|
||||||
|
#include <cligen/cligen.h>
|
||||||
|
|
||||||
|
#include "clixon_queue.h"
|
||||||
|
#include "clixon_hash.h"
|
||||||
|
#include "clixon_handle.h"
|
||||||
|
#include "clixon_yang.h"
|
||||||
|
#include "clixon_log.h"
|
||||||
|
#include "clixon_string.h"
|
||||||
|
#include "clixon_xml.h"
|
||||||
|
#include "clixon_xpath_ctx.h"
|
||||||
|
#include "clixon_xpath.h"
|
||||||
|
#include "clixon_xpath_parse.h"
|
||||||
|
|
||||||
|
/* Redefine main lex function so that you can send arguments to it: _yy is added to arg list */
|
||||||
|
#define YY_DECL int clixon_xpath_parselex(void *_yy)
|
||||||
|
|
||||||
|
/* Dont use input function (use user-buffer) */
|
||||||
|
#define YY_NO_INPUT
|
||||||
|
|
||||||
|
/* typecast macro */
|
||||||
|
#define _XY ((struct clicon_xpath_yacc_arg *)_yy)
|
||||||
|
|
||||||
|
#define MAXBUF 4*4*64*1024
|
||||||
|
|
||||||
|
#undef clixon_xpath_parsewrap
|
||||||
|
int
|
||||||
|
clixon_xpath_parsewrap(void)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
%}
|
||||||
|
|
||||||
|
digit [0-9]
|
||||||
|
integer {digit}+
|
||||||
|
real ({digit}+[.]{digit}*)|({digit}*[.]{digit}+)
|
||||||
|
|
||||||
|
%x TOKEN
|
||||||
|
%s QLITERAL
|
||||||
|
%s ALITERAL
|
||||||
|
|
||||||
|
%%
|
||||||
|
<TOKEN>[ \t]
|
||||||
|
<TOKEN>\n { _XY->xy_linenum++; }
|
||||||
|
<TOKEN>\r { }
|
||||||
|
<TOKEN><<EOF>> { return X_EOF; }
|
||||||
|
<TOKEN>".." { return DOUBLEDOT; }
|
||||||
|
<TOKEN>[()\[\]\.@,/:|] { return *yytext; }
|
||||||
|
<TOKEN>"::" { return DOUBLECOLON; }
|
||||||
|
<TOKEN>and { clixon_xpath_parselval.intval = clicon_str2int(xpopmap, yytext); return LOGOP; }
|
||||||
|
<TOKEN>or { clixon_xpath_parselval.intval = clicon_str2int(xpopmap, yytext); return LOGOP; }
|
||||||
|
<TOKEN>div { clixon_xpath_parselval.intval = clicon_str2int(xpopmap,yytext); return ADDOP; }
|
||||||
|
<TOKEN>mod { clixon_xpath_parselval.intval = clicon_str2int(xpopmap,yytext); return ADDOP; }
|
||||||
|
<TOKEN>[+*\-] { clixon_xpath_parselval.intval = clicon_str2int(xpopmap,yytext); return ADDOP; }
|
||||||
|
<TOKEN>\? { return *yytext; }
|
||||||
|
<TOKEN>"//" { return DOUBLESLASH; }
|
||||||
|
<TOKEN>"!=" { clixon_xpath_parselval.intval = clicon_str2int(xpopmap,yytext); return RELOP; }
|
||||||
|
<TOKEN>">=" { clixon_xpath_parselval.intval = clicon_str2int(xpopmap,yytext);return RELOP; }
|
||||||
|
<TOKEN>"<=" { clixon_xpath_parselval.intval = clicon_str2int(xpopmap,yytext);return RELOP; }
|
||||||
|
<TOKEN>[<>=] { clixon_xpath_parselval.intval = clicon_str2int(xpopmap,yytext);return RELOP; }
|
||||||
|
<TOKEN>last { clixon_xpath_parselval.string = strdup(yytext); return FUNCTIONNAME; }
|
||||||
|
<TOKEN>position { clixon_xpath_parselval.string = strdup(yytext); return FUNCTIONNAME; }
|
||||||
|
<TOKEN>count { clixon_xpath_parselval.string = strdup(yytext); return FUNCTIONNAME; }
|
||||||
|
<TOKEN>ancestor { clixon_xpath_parselval.intval = A_ANCESTOR; return AXISNAME; }
|
||||||
|
<TOKEN>ancestor-or-self { clixon_xpath_parselval.intval = A_ANCESTOR_OR_SELF; return AXISNAME; }
|
||||||
|
<TOKEN>attribute { clixon_xpath_parselval.intval = A_ATTRIBUTE; return AXISNAME; }
|
||||||
|
<TOKEN>child { clixon_xpath_parselval.intval = A_CHILD; return AXISNAME; }
|
||||||
|
<TOKEN>descendant { clixon_xpath_parselval.intval = A_DESCENDANT; return AXISNAME; }
|
||||||
|
<TOKEN>descendant-or-self { clixon_xpath_parselval.intval = A_DESCENDANT_OR_SELF; return AXISNAME; }
|
||||||
|
<TOKEN>following { clixon_xpath_parselval.intval = A_FOLLOWING; return AXISNAME; }
|
||||||
|
<TOKEN>following-sibling { clixon_xpath_parselval.intval = A_FOLLOWING_SIBLING; return AXISNAME; }
|
||||||
|
<TOKEN>namespace { clixon_xpath_parselval.intval = A_NAMESPACE; return AXISNAME; }
|
||||||
|
<TOKEN>parent { clixon_xpath_parselval.intval = A_PARENT; return AXISNAME; }
|
||||||
|
<TOKEN>preceding { clixon_xpath_parselval.intval = A_PRECEEDING; return AXISNAME; }
|
||||||
|
<TOKEN>preceding-sibling { clixon_xpath_parselval.intval = A_PRECEEDING_SIBLING; return AXISNAME; }
|
||||||
|
<TOKEN>self { clixon_xpath_parselval.intval = A_SELF; return AXISNAME; }
|
||||||
|
<TOKEN>current { clixon_xpath_parselval.string = strdup(yytext); return NODETYPE; }
|
||||||
|
<TOKEN>comment { clixon_xpath_parselval.string = strdup(yytext); return NODETYPE; }
|
||||||
|
<TOKEN>text { clixon_xpath_parselval.string = strdup(yytext); return NODETYPE; }
|
||||||
|
<TOKEN>processing-instructions { clixon_xpath_parselval.string = strdup(yytext); return NODETYPE; }
|
||||||
|
<TOKEN>node { clixon_xpath_parselval.string = strdup(yytext); return NODETYPE; }
|
||||||
|
<TOKEN>\" { BEGIN(QLITERAL); return QUOTE; }
|
||||||
|
<TOKEN>\' { BEGIN(ALITERAL); return APOST; }
|
||||||
|
<TOKEN>\-?({integer}|{real}) { sscanf(yytext,"%lf",&clixon_xpath_parselval.dval); return NUMBER;}
|
||||||
|
<TOKEN>[0-9A-Za-z_\-]+ { clixon_xpath_parselval.string = strdup(yytext);
|
||||||
|
return NAME; /* rather be catch-all */
|
||||||
|
}
|
||||||
|
<TOKEN>. { fprintf(stderr,"LEXICAL ERROR\n"); return -1; }
|
||||||
|
<QLITERAL>\" { BEGIN(TOKEN); return QUOTE; }
|
||||||
|
<QLITERAL>. { clixon_xpath_parselval.string = strdup(yytext);
|
||||||
|
return CHAR;}
|
||||||
|
<ALITERAL>\' { BEGIN(TOKEN); return APOST; }
|
||||||
|
<ALITERAL>. { clixon_xpath_parselval.string = strdup(yytext);
|
||||||
|
return CHAR;}
|
||||||
|
|
||||||
|
%%
|
||||||
|
|
||||||
|
|
||||||
|
/*! Initialize scanner.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
xpath_scan_init(struct clicon_xpath_yacc_arg *xy)
|
||||||
|
{
|
||||||
|
BEGIN(TOKEN);
|
||||||
|
xy->xy_lexbuf = yy_scan_string (xy->xy_parse_string);
|
||||||
|
#if 1 /* XXX: just to use unput to avoid warning */
|
||||||
|
if (0)
|
||||||
|
yyunput(0, "");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* free buffers
|
||||||
|
* Even within Flex version 2.5 (this is assumed), freeing buffers is different.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
xpath_scan_exit(struct clicon_xpath_yacc_arg *xy)
|
||||||
|
{
|
||||||
|
yy_delete_buffer(xy->xy_lexbuf);
|
||||||
|
clixon_xpath_parselex_destroy(); /* modern */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
289
lib/src/clixon_xpath_parse.y
Normal file
289
lib/src/clixon_xpath_parse.y
Normal file
|
|
@ -0,0 +1,289 @@
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
***** BEGIN LICENSE BLOCK *****
|
||||||
|
|
||||||
|
Copyright (C) 2009-2018 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 *****
|
||||||
|
|
||||||
|
* 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
|
||||||
|
* see https://www.w3.org/TR/xpath-10/#NT-Expr)
|
||||||
|
* Lexical structure is defined by ExprToken, see
|
||||||
|
* see https://www.w3.org/TR/xpath-10/#exprlex
|
||||||
|
*/
|
||||||
|
|
||||||
|
%start start
|
||||||
|
|
||||||
|
%union {
|
||||||
|
int intval;
|
||||||
|
double dval;
|
||||||
|
char *string;
|
||||||
|
void *stack; /* xpath_tree */
|
||||||
|
}
|
||||||
|
|
||||||
|
%token <intval> AXISNAME
|
||||||
|
%token <intval> LOGOP
|
||||||
|
%token <intval> ADDOP
|
||||||
|
%token <intval> RELOP
|
||||||
|
|
||||||
|
%token <dval> NUMBER
|
||||||
|
|
||||||
|
%token <string> X_EOF
|
||||||
|
%token <string> QUOTE
|
||||||
|
%token <string> APOST
|
||||||
|
%token <string> CHAR
|
||||||
|
%token <string> NAME
|
||||||
|
%token <string> NODETYPE
|
||||||
|
%token <string> DOUBLEDOT
|
||||||
|
%token <string> DOUBLECOLON
|
||||||
|
%token <string> DOUBLESLASH
|
||||||
|
%token <string> FUNCTIONNAME
|
||||||
|
|
||||||
|
%type <intval> axisspec
|
||||||
|
|
||||||
|
%type <string> string
|
||||||
|
%type <stack> expr
|
||||||
|
%type <stack> andexpr
|
||||||
|
%type <stack> relexpr
|
||||||
|
%type <stack> addexpr
|
||||||
|
%type <stack> unionexpr
|
||||||
|
%type <stack> pathexpr
|
||||||
|
%type <stack> locationpath
|
||||||
|
%type <stack> abslocpath
|
||||||
|
%type <stack> rellocpath
|
||||||
|
%type <stack> step
|
||||||
|
%type <stack> nodetest
|
||||||
|
%type <stack> predicates
|
||||||
|
%type <stack> primaryexpr
|
||||||
|
|
||||||
|
%lex-param {void *_xy} /* Add this argument to parse() and lex() function */
|
||||||
|
%parse-param {void *_xy}
|
||||||
|
|
||||||
|
%{
|
||||||
|
/* Here starts user C-code */
|
||||||
|
|
||||||
|
/* typecast macro */
|
||||||
|
#define _XY ((struct clicon_xpath_yacc_arg *)_xy)
|
||||||
|
|
||||||
|
#define _YYERROR(msg) {clicon_err(OE_XML, 0, "YYERROR %s '%s' %d", (msg), clixon_xpath_parsetext, _XY->xy_linenum); YYERROR;}
|
||||||
|
|
||||||
|
/* add _yy to error paramaters */
|
||||||
|
#define YY_(msgid) msgid
|
||||||
|
|
||||||
|
#include "clixon_config.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fnmatch.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <net/if.h>
|
||||||
|
|
||||||
|
#include <cligen/cligen.h>
|
||||||
|
|
||||||
|
#include "clixon_err.h"
|
||||||
|
#include "clixon_log.h"
|
||||||
|
#include "clixon_queue.h"
|
||||||
|
#include "clixon_string.h"
|
||||||
|
#include "clixon_hash.h"
|
||||||
|
#include "clixon_handle.h"
|
||||||
|
#include "clixon_yang.h"
|
||||||
|
#include "clixon_xml.h"
|
||||||
|
#include "clixon_xpath_ctx.h"
|
||||||
|
#include "clixon_xpath.h"
|
||||||
|
|
||||||
|
#include "clixon_xpath_parse.h"
|
||||||
|
|
||||||
|
extern int clixon_xpath_parseget_lineno (void);
|
||||||
|
|
||||||
|
/*
|
||||||
|
also called from yacc generated code *
|
||||||
|
*/
|
||||||
|
|
||||||
|
void
|
||||||
|
clixon_xpath_parseerror(void *_xy,
|
||||||
|
char *s)
|
||||||
|
{
|
||||||
|
clicon_err(OE_XML, 0, "%s on line %d: %s at or before: '%s'",
|
||||||
|
_XY->xy_name,
|
||||||
|
_XY->xy_linenum ,
|
||||||
|
s,
|
||||||
|
clixon_xpath_parsetext);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
xpath_parse_init(struct clicon_xpath_yacc_arg *xy)
|
||||||
|
{
|
||||||
|
// clicon_debug_init(2, NULL);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
xpath_parse_exit(struct clicon_xpath_yacc_arg *xy)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static xpath_tree *
|
||||||
|
xp_new(enum xp_type type,
|
||||||
|
int i0,
|
||||||
|
double d0,
|
||||||
|
char *s0,
|
||||||
|
char *s1,
|
||||||
|
xpath_tree *c0,
|
||||||
|
xpath_tree *c1)
|
||||||
|
{
|
||||||
|
xpath_tree *xs = NULL;
|
||||||
|
|
||||||
|
if ((xs = malloc(sizeof(xpath_tree))) == NULL){
|
||||||
|
clicon_err(OE_XML, errno, "malloc");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
memset(xs, 0, sizeof(*xs));
|
||||||
|
xs->xs_type = type;
|
||||||
|
xs->xs_int = i0;
|
||||||
|
xs->xs_double = d0;
|
||||||
|
xs->xs_s0 = s0;
|
||||||
|
xs->xs_s1 = s1;
|
||||||
|
xs->xs_c0 = c0;
|
||||||
|
xs->xs_c1 = c1;
|
||||||
|
done:
|
||||||
|
return xs;
|
||||||
|
}
|
||||||
|
|
||||||
|
%}
|
||||||
|
|
||||||
|
%%
|
||||||
|
|
||||||
|
/*
|
||||||
|
*/
|
||||||
|
|
||||||
|
start : expr X_EOF { _XY->xy_top=$1;clicon_debug(1,"start->expr"); YYACCEPT; }
|
||||||
|
| locationpath X_EOF { _XY->xy_top=$1;clicon_debug(1,"start->locationpath"); YYACCEPT; }
|
||||||
|
;
|
||||||
|
|
||||||
|
expr : expr LOGOP andexpr { $$=xp_new(XP_EXP,$2,0.0,NULL,NULL,$1, $3);clicon_debug(1,"expr->expr or andexpr"); }
|
||||||
|
| andexpr { $$=xp_new(XP_EXP,A_NAN,0.0,NULL,NULL,$1, NULL);clicon_debug(1,"expr-> andexpr"); }
|
||||||
|
;
|
||||||
|
|
||||||
|
andexpr : andexpr LOGOP relexpr { $$=xp_new(XP_AND,$2,0.0,NULL,NULL,$1, $3);clicon_debug(1,"andexpr-> andexpr and relexpr"); }
|
||||||
|
| relexpr { $$=xp_new(XP_AND,A_NAN,0.0,NULL,NULL,$1, NULL);clicon_debug(1,"andexpr-> relexpr"); }
|
||||||
|
;
|
||||||
|
|
||||||
|
relexpr : relexpr RELOP addexpr { $$=xp_new(XP_RELEX,$2,0.0,NULL,NULL,$1, $3);clicon_debug(1,"relexpr-> relexpr relop addexpr"); }
|
||||||
|
| addexpr { $$=xp_new(XP_RELEX,A_NAN,0.0,NULL,NULL,$1, NULL);clicon_debug(1,"relexpr-> addexpr"); }
|
||||||
|
;
|
||||||
|
|
||||||
|
addexpr : addexpr ADDOP unionexpr { $$=xp_new(XP_ADD,$2,0.0,NULL,NULL,$1, $3);clicon_debug(1,"addexpr-> addexpr ADDOP unionexpr"); }
|
||||||
|
| unionexpr { $$=xp_new(XP_ADD,A_NAN,0.0,NULL,NULL,$1, NULL);clicon_debug(1,"addexpr-> unionexpr"); }
|
||||||
|
;
|
||||||
|
|
||||||
|
/* node-set */
|
||||||
|
unionexpr : unionexpr '|' pathexpr { $$=xp_new(XP_UNION,A_NAN,0.0,NULL,NULL,$1, $3);clicon_debug(1,"unionexpr-> unionexpr | pathexpr"); }
|
||||||
|
| pathexpr { $$=xp_new(XP_UNION,A_NAN,0.0,NULL,NULL,$1, NULL);clicon_debug(1,"unionexpr-> pathexpr"); }
|
||||||
|
;
|
||||||
|
|
||||||
|
pathexpr : locationpath { $$=xp_new(XP_PATHEXPR,A_NAN,0.0,NULL,NULL,$1, NULL);clicon_debug(1,"pathexpr-> locationpath"); }
|
||||||
|
| primaryexpr { $$=xp_new(XP_PATHEXPR,A_NAN,0.0,NULL,NULL,$1, NULL);clicon_debug(1,"pathexpr-> primaryexpr"); }
|
||||||
|
;
|
||||||
|
|
||||||
|
/* location path returns a node-set */
|
||||||
|
locationpath : rellocpath { $$=xp_new(XP_LOCPATH,A_NAN,0.0,NULL,NULL,$1, NULL); clicon_debug(1,"locationpath-> rellocpath"); }
|
||||||
|
| abslocpath { $$=xp_new(XP_LOCPATH,A_NAN,0.0,NULL,NULL,$1, NULL); clicon_debug(1,"locationpath-> abslocpath"); }
|
||||||
|
;
|
||||||
|
|
||||||
|
abslocpath : '/' { $$=xp_new(XP_ABSPATH,A_ROOT,0.0,NULL,NULL,NULL, NULL);clicon_debug(1,"abslocpath-> /"); }
|
||||||
|
| '/' rellocpath { $$=xp_new(XP_ABSPATH,A_ROOT,0.0,NULL,NULL,$2, NULL);clicon_debug(1,"abslocpath->/ rellocpath");}
|
||||||
|
/* // is short for /descendant-or-self::node()/ */
|
||||||
|
| DOUBLESLASH rellocpath {$$=xp_new(XP_ABSPATH,A_DESCENDANT_OR_SELF,0.0,NULL,NULL,$2, NULL); clicon_debug(1,"abslocpath-> // rellocpath"); }
|
||||||
|
;
|
||||||
|
|
||||||
|
rellocpath : step { $$=xp_new(XP_RELLOCPATH,A_NAN,0.0,NULL,NULL,$1, NULL); clicon_debug(1,"rellocpath-> step"); }
|
||||||
|
| rellocpath '/' step { $$=xp_new(XP_RELLOCPATH,A_NAN,0.0,NULL,NULL,$1, $3);clicon_debug(1,"rellocpath-> rellocpath / step"); }
|
||||||
|
| rellocpath DOUBLESLASH step { $$=xp_new(XP_RELLOCPATH,A_DESCENDANT_OR_SELF,0.0,NULL,NULL,$1, $3); clicon_debug(1,"rellocpath-> rellocpath // step"); }
|
||||||
|
;
|
||||||
|
|
||||||
|
step : axisspec nodetest predicates {$$=xp_new(XP_STEP,$1,0.0, NULL, NULL, $2, $3);clicon_debug(1,"step->axisspec(%d) nodetest", $1); }
|
||||||
|
| '.' predicates { $$=xp_new(XP_STEP,A_SELF, 0.0,NULL, NULL, NULL, $2); clicon_debug(1,"step-> ."); }
|
||||||
|
| DOUBLEDOT predicates { $$=xp_new(XP_STEP, A_PARENT, 0.0,NULL, NULL, NULL, $2); clicon_debug(1,"step-> .."); }
|
||||||
|
;
|
||||||
|
|
||||||
|
axisspec : AXISNAME DOUBLECOLON { clicon_debug(1,"axisspec-> AXISNAME(%d) ::", $1); $$=$1;}
|
||||||
|
| '@' { $$=A_ATTRIBUTE; clicon_debug(1,"axisspec-> @"); }
|
||||||
|
| { clicon_debug(1,"axisspec-> "); $$=A_CHILD;}
|
||||||
|
;
|
||||||
|
|
||||||
|
nodetest : '*' { $$=xp_new(XP_NODE,A_NAN,0.0, NULL, NULL, NULL, NULL); clicon_debug(1,"nodetest-> *"); }
|
||||||
|
| NAME { $$=xp_new(XP_NODE,A_NAN,0.0, NULL, $1, NULL, NULL); clicon_debug(1,"nodetest-> name(%s)",$1); }
|
||||||
|
| NAME ':' NAME { $$=xp_new(XP_NODE,A_NAN,0.0, $1, $3, NULL, NULL);clicon_debug(1,"nodetest-> name(%s) : name(%s)", $1, $3); }
|
||||||
|
| NAME ':' '*' { $$=xp_new(XP_NODE,A_NAN,0.0, $1, NULL, NULL, NULL);clicon_debug(1,"nodetest-> name(%s) : *", $1); }
|
||||||
|
| NODETYPE '(' ')' { $$=xp_new(XP_NODE_FN,A_NAN,0.0, $1, NULL, NULL, NULL); clicon_debug(1,"nodetest-> nodetype()"); }
|
||||||
|
;
|
||||||
|
|
||||||
|
/* evaluates to boolean */
|
||||||
|
predicates : predicates '[' expr ']' { $$=xp_new(XP_PRED,A_NAN,0.0, NULL, NULL, $1, $3); clicon_debug(1,"predicates-> [ expr ]"); }
|
||||||
|
| { $$=xp_new(XP_PRED,A_NAN,0.0, NULL, NULL, NULL, NULL); clicon_debug(1,"predicates->"); }
|
||||||
|
;
|
||||||
|
|
||||||
|
primaryexpr : '(' expr ')' { $$=xp_new(XP_PRI0,A_NAN,0.0, NULL, NULL, $2, NULL); clicon_debug(1,"primaryexpr-> ( expr )"); }
|
||||||
|
| NUMBER { $$=xp_new(XP_PRIME_NR,A_NAN, $1, NULL, NULL, NULL, NULL);clicon_debug(1,"primaryexpr-> NUMBER(%lf)", $1); }
|
||||||
|
| QUOTE string QUOTE { $$=xp_new(XP_PRIME_STR,A_NAN,0.0, $2, NULL, NULL, NULL);clicon_debug(1,"primaryexpr-> \" string \""); }
|
||||||
|
| QUOTE QUOTE { $$=xp_new(XP_PRIME_STR,A_NAN,0.0, NULL, NULL, NULL, NULL);clicon_debug(1,"primaryexpr-> \" \""); }
|
||||||
|
| APOST string APOST { $$=xp_new(XP_PRIME_STR,A_NAN,0.0, $2, NULL, NULL, NULL);clicon_debug(1,"primaryexpr-> ' string '"); }
|
||||||
|
| APOST APOST { $$=xp_new(XP_PRIME_STR,A_NAN,0.0, NULL, NULL, NULL, NULL);clicon_debug(1,"primaryexpr-> ' '"); }
|
||||||
|
| FUNCTIONNAME '(' ')' { $$=xp_new(XP_PRIME_FN,A_NAN,0.0, $1, NULL, NULL, NULL);clicon_debug(1,"primaryexpr-> functionname ( arguments )"); }
|
||||||
|
;
|
||||||
|
|
||||||
|
/* XXX Adding this between FUNCTIONNAME() breaks parser,..
|
||||||
|
arguments : arguments expr { clicon_debug(1,"arguments-> arguments expr"); }
|
||||||
|
| { clicon_debug(1,"arguments-> "); }
|
||||||
|
;
|
||||||
|
*/
|
||||||
|
string : string CHAR {
|
||||||
|
int len = strlen($1);
|
||||||
|
$$ = realloc($1, len+strlen($2) + 1);
|
||||||
|
sprintf($$+len, "%s", $2);
|
||||||
|
free($2);
|
||||||
|
clicon_debug(1,"string-> string CHAR");
|
||||||
|
}
|
||||||
|
| CHAR { clicon_debug(1,"string-> "); }
|
||||||
|
;
|
||||||
|
|
||||||
|
|
||||||
|
%%
|
||||||
|
|
||||||
|
|
@ -35,55 +35,17 @@
|
||||||
* NOTE: there is a main function at the end of this file where you can test out
|
* NOTE: there is a main function at the end of this file where you can test out
|
||||||
* different xpath expressions.
|
* different xpath expressions.
|
||||||
* Look at the end of the file for a test unit program
|
* Look at the end of the file for a test unit program
|
||||||
|
|
||||||
|
The code is implemented according to XPATH 1.0:
|
||||||
|
https://www.w3.org/TR/xpath-10/
|
||||||
|
|
||||||
|
The primary syntactic construct in XPath is the expression. An expression matches
|
||||||
|
the production Expr (see https://www.w3.org/TR/xpath-10/#NT-Expr)
|
||||||
*/
|
*/
|
||||||
/*
|
#ifdef HAVE_CONFIG_H
|
||||||
See https://www.w3.org/TR/xpath/
|
#include "clixon_config.h" /* generated by config & autoconf */
|
||||||
|
#endif
|
||||||
|
|
||||||
Implementation of a limited xslt xpath syntax. Some examples. Given the following
|
|
||||||
xml tree:
|
|
||||||
<aaa>
|
|
||||||
<bbb x="hello"><ccc>42</ccc></bbb>
|
|
||||||
<bbb x="bye"><ccc>99</ccc></bbb>
|
|
||||||
<ddd><ccc>22</ccc></ddd>
|
|
||||||
</aaa>
|
|
||||||
|
|
||||||
With the following xpath examples. There are some diffs and many limitations compared
|
|
||||||
to the xml standards:
|
|
||||||
/ whole tree <aaa>...</aaa>
|
|
||||||
/bbb
|
|
||||||
/aaa/bbb <bbb x="hello"><ccc>42</ccc></bbb>
|
|
||||||
<bbb x="bye"><ccc>99</ccc></bbb>
|
|
||||||
//bbb as above
|
|
||||||
//b?b as above
|
|
||||||
//b\* as above
|
|
||||||
//b\*\/ccc <ccc>42</ccc>
|
|
||||||
<ccc>99</ccc>
|
|
||||||
//\*\/ccc <ccc>42</ccc>
|
|
||||||
<ccc>99</ccc>
|
|
||||||
<ccc>22</ccc>
|
|
||||||
-- //bbb@x x="hello"
|
|
||||||
//bbb[@x] <bbb x="hello"><ccc>42</ccc></bbb>
|
|
||||||
<bbb x="bye"><ccc>99</ccc></bbb>
|
|
||||||
//bbb[@x=hello] <bbb x="hello"><ccc>42</ccc></bbb>
|
|
||||||
//bbb[@x="hello"] as above
|
|
||||||
//bbb[0] <bbb x="hello"><ccc>42</ccc></bbb>
|
|
||||||
//bbb[ccc=99] <bbb x="bye"><ccc>99</ccc></bbb>
|
|
||||||
--- //\*\/[ccc=99] same as above
|
|
||||||
'//bbb | //ddd' <bbb><ccc>42</ccc></bbb>
|
|
||||||
<bbb x="hello"><ccc>99</ccc></bbb>
|
|
||||||
<ddd><ccc>22</ccc></ddd> (NB spaces)
|
|
||||||
etc
|
|
||||||
For xpath v1.0 see http://www.w3.org/TR/xpath/
|
|
||||||
record[name=c][time=d]
|
|
||||||
in
|
|
||||||
<record>
|
|
||||||
<name>c</name>
|
|
||||||
<time>d</time>
|
|
||||||
<userid>45654df4-2292-45d3-9ca5-ee72452568a8</userid>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
|
|
||||||
*/
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
@ -94,6 +56,8 @@ in
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <syslog.h>
|
#include <syslog.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
/* cligen */
|
/* cligen */
|
||||||
#include <cligen/cligen.h>
|
#include <cligen/cligen.h>
|
||||||
|
|
@ -107,14 +71,18 @@ in
|
||||||
#include "clixon_handle.h"
|
#include "clixon_handle.h"
|
||||||
#include "clixon_yang.h"
|
#include "clixon_yang.h"
|
||||||
#include "clixon_xml.h"
|
#include "clixon_xml.h"
|
||||||
|
#include "clixon_xpath_ctx.h"
|
||||||
|
#include "clixon_xpath.h"
|
||||||
#include "clixon_xsl.h"
|
#include "clixon_xsl.h"
|
||||||
|
|
||||||
|
|
||||||
/* Constants */
|
/* Constants */
|
||||||
#define XPATH_VEC_START 128
|
#define XPATH_VEC_START 128
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Types
|
* Types
|
||||||
*/
|
*/
|
||||||
|
|
||||||
struct searchvec{
|
struct searchvec{
|
||||||
cxobj **sv_v0; /* here is result */
|
cxobj **sv_v0; /* here is result */
|
||||||
int sv_v0len;
|
int sv_v0len;
|
||||||
|
|
@ -126,13 +94,22 @@ typedef struct searchvec searchvec;
|
||||||
|
|
||||||
/* Local types
|
/* Local types
|
||||||
*/
|
*/
|
||||||
enum axis_type{
|
|
||||||
A_SELF,
|
struct xpath_predicate{
|
||||||
A_CHILD,
|
struct xpath_predicate *xp_next;
|
||||||
A_PARENT,
|
char *xp_expr;
|
||||||
A_ROOT,
|
};
|
||||||
A_ANCESTOR,
|
|
||||||
A_DESCENDANT_OR_SELF, /* actually descendant-or-self */
|
/* XPATH Axis according to https://www.w3.org/TR/xpath-10/#NT-Step
|
||||||
|
* Axis ::= AxisSpecifier NodeTest Predicate*
|
||||||
|
* Eg "child::
|
||||||
|
*/
|
||||||
|
struct xpath_element{
|
||||||
|
struct xpath_element *xe_next;
|
||||||
|
enum axis_type xe_type;
|
||||||
|
char *xe_prefix; /* eg for namespaces */
|
||||||
|
char *xe_str; /* eg for child */
|
||||||
|
struct xpath_predicate *xe_predicate; /* eg within [] */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Mapping between axis type string <--> int */
|
/* Mapping between axis type string <--> int */
|
||||||
|
|
@ -146,23 +123,12 @@ static const map_str2int axismap[] = {
|
||||||
{NULL, -1}
|
{NULL, -1}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct xpath_predicate{
|
|
||||||
struct xpath_predicate *xp_next;
|
|
||||||
char *xp_expr;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct xpath_element{
|
|
||||||
struct xpath_element *xe_next;
|
|
||||||
enum axis_type xe_type;
|
|
||||||
char *xe_prefix; /* eg for namespaces */
|
|
||||||
char *xe_str; /* eg for child */
|
|
||||||
struct xpath_predicate *xe_predicate; /* eg within [] */
|
|
||||||
};
|
|
||||||
|
|
||||||
static int xpath_split(char *xpathstr, char **pathexpr);
|
static int xpath_split(char *xpathstr, char **pathexpr);
|
||||||
|
|
||||||
|
/*! Print xpath structure for debug */
|
||||||
static int
|
static int
|
||||||
xpath_print(FILE *f, struct xpath_element *xplist)
|
xpath_print(FILE *f,
|
||||||
|
struct xpath_element *xplist)
|
||||||
{
|
{
|
||||||
struct xpath_element *xe;
|
struct xpath_element *xe;
|
||||||
struct xpath_predicate *xp;
|
struct xpath_predicate *xp;
|
||||||
|
|
@ -204,7 +170,7 @@ xpath_parse_predicate(struct xpath_element *xe,
|
||||||
}
|
}
|
||||||
memset(xp, 0, sizeof(*xp));
|
memset(xp, 0, sizeof(*xp));
|
||||||
if ((xp->xp_expr = strdup(s)) == NULL){
|
if ((xp->xp_expr = strdup(s)) == NULL){
|
||||||
clicon_err(OE_XML, errno, "%s: strdup", __FUNCTION__);
|
clicon_err(OE_XML, errno, "strdup");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
xp->xp_next = xe->xe_predicate;
|
xp->xp_next = xe->xe_predicate;
|
||||||
|
|
@ -216,6 +182,11 @@ xpath_parse_predicate(struct xpath_element *xe,
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! XPATH parse, create new child element
|
||||||
|
* @param[in] atype Axis type, see https://www.w3.org/TR/xpath-10/#axes
|
||||||
|
* @param[in] str
|
||||||
|
* @param[out] xpnext
|
||||||
|
*/
|
||||||
static int
|
static int
|
||||||
xpath_element_new(enum axis_type atype,
|
xpath_element_new(enum axis_type atype,
|
||||||
char *str,
|
char *str,
|
||||||
|
|
@ -235,7 +206,7 @@ xpath_element_new(enum axis_type atype,
|
||||||
xe->xe_type = atype;
|
xe->xe_type = atype;
|
||||||
if (str){
|
if (str){
|
||||||
if ((str1 = strdup(str)) == NULL){
|
if ((str1 = strdup(str)) == NULL){
|
||||||
clicon_err(OE_XML, errno, "%s: strdup", __FUNCTION__);
|
clicon_err(OE_XML, errno, "strdup");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (xpath_split(str1, &pred) < 0) /* Can be more predicates */
|
if (xpath_split(str1, &pred) < 0) /* Can be more predicates */
|
||||||
|
|
@ -246,20 +217,20 @@ xpath_element_new(enum axis_type atype,
|
||||||
*local = '\0';
|
*local = '\0';
|
||||||
local++;
|
local++;
|
||||||
if ((xe->xe_prefix = strdup(str1)) == NULL){
|
if ((xe->xe_prefix = strdup(str1)) == NULL){
|
||||||
clicon_err(OE_XML, errno, "%s: strdup", __FUNCTION__);
|
clicon_err(OE_XML, errno, "strdup");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
local = str1;
|
local = str1;
|
||||||
if ((xe->xe_str = strdup(local)) == NULL){
|
if ((xe->xe_str = strdup(local)) == NULL){
|
||||||
clicon_err(OE_XML, errno, "%s: strdup", __FUNCTION__);
|
clicon_err(OE_XML, errno, "strdup");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
if ((xe->xe_str = strdup("*")) == NULL){
|
if ((xe->xe_str = strdup("*")) == NULL){
|
||||||
clicon_err(OE_XML, errno, "%s: strdup", __FUNCTION__);
|
clicon_err(OE_XML, errno, "strdup");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -308,8 +279,17 @@ xpath_free(struct xpath_element *xplist)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*! Parse xpath to xpath_element structure
|
||||||
* // is short for /descendant-or-self::node()/
|
|
||||||
|
*
|
||||||
|
* [1] LocationPath ::= RelativeLocationPath
|
||||||
|
* | AbsoluteLocationPath
|
||||||
|
* [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
|
||||||
|
* | AbbreviatedAbsoluteLocationPath
|
||||||
|
* [3] RelativeLocationPath ::= Step
|
||||||
|
| RelativeLocationPath '/' Step
|
||||||
|
| AbbreviatedRelativeLocationPath
|
||||||
|
* @see https://www.w3.org/TR/xpath-10/#NT-LocationPath
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
xpath_parse(char *xpath,
|
xpath_parse(char *xpath,
|
||||||
|
|
@ -325,7 +305,7 @@ xpath_parse(char *xpath,
|
||||||
int esc = 0;
|
int esc = 0;
|
||||||
|
|
||||||
if ((s0 = strdup(xpath)) == NULL){
|
if ((s0 = strdup(xpath)) == NULL){
|
||||||
clicon_err(OE_XML, errno, "%s: strdup", __FUNCTION__);
|
clicon_err(OE_XML, errno, "strdup");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
s = s0;
|
s = s0;
|
||||||
|
|
@ -354,6 +334,7 @@ xpath_parse(char *xpath,
|
||||||
}
|
}
|
||||||
s++;
|
s++;
|
||||||
}
|
}
|
||||||
|
/* Iterate through steps (s), see https://www.w3.org/TR/xpath-10/#NT-Step */
|
||||||
s = s0;
|
s = s0;
|
||||||
for (i=0; i<nvec; i++){
|
for (i=0; i<nvec; i++){
|
||||||
if ((i==0 && strcmp(s,"")==0)) /* Initial / or // */
|
if ((i==0 && strcmp(s,"")==0)) /* Initial / or // */
|
||||||
|
|
@ -363,21 +344,10 @@ xpath_parse(char *xpath,
|
||||||
else if (strncmp(s,"descendant-or-self::", strlen("descendant-or-self::"))==0){
|
else if (strncmp(s,"descendant-or-self::", strlen("descendant-or-self::"))==0){
|
||||||
xpath_element_new(A_DESCENDANT_OR_SELF, s+strlen("descendant-or-self::"), &xpnext);
|
xpath_element_new(A_DESCENDANT_OR_SELF, s+strlen("descendant-or-self::"), &xpnext);
|
||||||
}
|
}
|
||||||
#if 1
|
|
||||||
else if (strncmp(s,"..", strlen(".."))==0) /* abbreviatedstep */
|
else if (strncmp(s,"..", strlen(".."))==0) /* abbreviatedstep */
|
||||||
xpath_element_new(A_PARENT, s+strlen(".."), &xpnext);
|
xpath_element_new(A_PARENT, s+strlen(".."), &xpnext);
|
||||||
#else
|
|
||||||
else if (strncmp(s,"..", strlen(s))==0) /* abbreviatedstep */
|
|
||||||
xpath_element_new(A_PARENT, NULL, &xpnext);
|
|
||||||
#endif
|
|
||||||
#if 1 /* Problems with .[userid=1321] */
|
|
||||||
else if (strncmp(s,".", strlen("."))==0)
|
else if (strncmp(s,".", strlen("."))==0)
|
||||||
xpath_element_new(A_SELF, s+strlen("."), &xpnext);
|
xpath_element_new(A_SELF, s+strlen("."), &xpnext);
|
||||||
#else
|
|
||||||
else if (strncmp(s,".", strlen(s))==0) /* abbreviatedstep */
|
|
||||||
xpath_element_new(A_SELF, NULL, &xpnext);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
else if (strncmp(s,"self::", strlen("self::"))==0)
|
else if (strncmp(s,"self::", strlen("self::"))==0)
|
||||||
xpath_element_new(A_SELF, s+strlen("self::"), &xpnext);
|
xpath_element_new(A_SELF, s+strlen("self::"), &xpnext);
|
||||||
|
|
||||||
|
|
@ -404,23 +374,21 @@ xpath_parse(char *xpath,
|
||||||
*
|
*
|
||||||
* The xv_* arguments are filled in nodes found earlier.
|
* The xv_* arguments are filled in nodes found earlier.
|
||||||
* args:
|
* args:
|
||||||
* @param[in] xn_parent Base XML object
|
* @param[in] xn_parent Base XML object
|
||||||
* @param[in] name shell wildcard pattern to match with node name
|
* @param[in] pattern Shell wildcard pattern to match with node name
|
||||||
* @param[in] node_type CX_ELMNT, CX_ATTR or CX_BODY
|
* @param[in] node_type CX_ELMNT, CX_ATTR or CX_BODY
|
||||||
* @param[in,out] vec1 internal buffers with results
|
* @param[in,out] vec0 Internal buffers with results
|
||||||
* @param[in,out] vec0 internal buffers with results
|
* @param[in,out] vec0len Internal buffers with length of vec0
|
||||||
* @param[in,out] vec_len internal buffers with length of vec0,vec1
|
|
||||||
* @param[in,out] vec_max internal buffers with max of vec0,vec1
|
|
||||||
* returns:
|
* returns:
|
||||||
* 0 on OK, -1 on error
|
* 0 on OK, -1 on error
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
recursive_find(cxobj *xn,
|
xpath_recursive_find(cxobj *xn,
|
||||||
char *pattern,
|
char *pattern,
|
||||||
int node_type,
|
int node_type,
|
||||||
uint16_t flags,
|
uint16_t flags,
|
||||||
cxobj ***vec0,
|
cxobj ***vec0,
|
||||||
size_t *vec0len)
|
size_t *vec0len)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
cxobj *xsub;
|
cxobj *xsub;
|
||||||
|
|
@ -438,7 +406,7 @@ recursive_find(cxobj *xn,
|
||||||
goto done;
|
goto done;
|
||||||
// continue; /* Dont go deeper */
|
// continue; /* Dont go deeper */
|
||||||
}
|
}
|
||||||
if (recursive_find(xsub, pattern, node_type, flags, &vec, &veclen) < 0)
|
if (xpath_recursive_find(xsub, pattern, node_type, flags, &vec, &veclen) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
retval = 0;
|
retval = 0;
|
||||||
|
|
@ -501,8 +469,7 @@ xpath_expr(cxobj *xcur,
|
||||||
e_v=e;
|
e_v=e;
|
||||||
e_a = strsep(&e_v, "=");
|
e_a = strsep(&e_v, "=");
|
||||||
if (e_a == NULL){
|
if (e_a == NULL){
|
||||||
clicon_err(OE_XML, errno, "%s: malformed expression: [@%s]",
|
clicon_err(OE_XML, errno, "malformed expression: [@%s]", e);
|
||||||
__FUNCTION__, e);
|
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
for (i=0; i<*vec0len; i++){
|
for (i=0; i<*vec0len; i++){
|
||||||
|
|
@ -533,15 +500,13 @@ xpath_expr(cxobj *xcur,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
clicon_err(OE_XML, errno, "%s: malformed expression: [%s]",
|
clicon_err(OE_XML, errno, "malformed expression: [%s]", e);
|
||||||
__FUNCTION__, e);
|
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else{ /* name = expr */
|
else{ /* name = expr */
|
||||||
if ((tag = strsep(&e, "=")) == NULL){
|
if ((tag = strsep(&e, "=")) == NULL){
|
||||||
clicon_err(OE_XML, errno, "%s: malformed expression: [%s]",
|
clicon_err(OE_XML, errno, "malformed expression: [%s]", e);
|
||||||
__FUNCTION__, e);
|
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
/* Strip trailing spaces */
|
/* Strip trailing spaces */
|
||||||
|
|
@ -697,7 +662,7 @@ xpath_find(cxobj *xcur,
|
||||||
if (descendants0){
|
if (descendants0){
|
||||||
for (i=0; i<vec0len; i++){
|
for (i=0; i<vec0len; i++){
|
||||||
xv = vec0[i];
|
xv = vec0[i];
|
||||||
if (recursive_find(xv, xe->xe_str, CX_ELMNT, flags, &vec1, &vec1len) < 0)
|
if (xpath_recursive_find(xv, xe->xe_str, CX_ELMNT, flags, &vec1, &vec1len) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -740,7 +705,6 @@ xpath_find(cxobj *xcur,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (xp = xe->xe_predicate; xp; xp = xp->xp_next){
|
for (xp = xe->xe_predicate; xp; xp = xp->xp_next){
|
||||||
if (xpath_expr(xcur, xp->xp_expr, flags, &vec0, &vec0len) < 0)
|
if (xpath_expr(xcur, xp->xp_expr, flags, &vec0, &vec0len) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -781,7 +745,7 @@ xpath_split(char *xpathstr,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (pe==NULL){
|
if (pe==NULL){
|
||||||
clicon_err(OE_XML, errno, "%s: mismatched []: %s", __FUNCTION__, xpathstr);
|
clicon_err(OE_XML, errno, "mismatched []: %s", xpathstr);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -800,6 +764,7 @@ xpath_split(char *xpathstr,
|
||||||
* @param[in] flags if != 0, only match xml nodes matching flags
|
* @param[in] flags if != 0, only match xml nodes matching flags
|
||||||
* @param[out] vec2 Result XML node vector
|
* @param[out] vec2 Result XML node vector
|
||||||
* @param[out] vec2len Length of result vector.
|
* @param[out] vec2len Length of result vector.
|
||||||
|
* @see https://www.w3.org/TR/xpath-10/#NT-LocationPath
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
xpath_exec(cxobj *xcur,
|
xpath_exec(cxobj *xcur,
|
||||||
|
|
@ -833,14 +798,20 @@ xpath_exec(cxobj *xcur,
|
||||||
* @param[in] xcur xml-tree where to search
|
* @param[in] xcur xml-tree where to search
|
||||||
* @param[in] xpath string with XPATH syntax
|
* @param[in] xpath string with XPATH syntax
|
||||||
* @param[in] flags if != 0, only match xml nodes matching flags
|
* @param[in] flags if != 0, only match xml nodes matching flags
|
||||||
* @param[in] vec1 vector of XML trees
|
* @param[out] vec1 vector of XML trees
|
||||||
* @param[in] vec1len length of XML trees
|
* @param[out] vec1len length of XML trees
|
||||||
* For example: xpath = //a | //b.
|
* For example: xpath = //a | //b.
|
||||||
* xpath_first+ splits xpath up in several subcalls
|
* xpath_first+ splits xpath up in several subcalls
|
||||||
* (eg xpath=//a and xpath=//b) and collects the results.
|
* (eg xpath=//a and xpath=//b) and collects the results.
|
||||||
* Note: if a match is found in both, two (or more) same results will be
|
* Note: if a match is found in both, two (or more) same results will be
|
||||||
* returned.
|
* returned.
|
||||||
* Note, this could be 'folded' into xpath1 but I judged it too complex.
|
* Note, this could be 'folded' into xpath1 but I judged it too complex.
|
||||||
|
* @see https://www.w3.org/TR/xpath-10/#NT-Expr
|
||||||
|
* An 'Expr' is composed of compositions of and, or, =, +, -, down to:
|
||||||
|
* PathExpr ::= LocationPath
|
||||||
|
* | FilterExpr
|
||||||
|
* | FilterExpr '/' RelativeLocationPath
|
||||||
|
* | FilterExpr '//' RelativeLocationPath
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
xpath_choice(cxobj *xcur,
|
xpath_choice(cxobj *xcur,
|
||||||
|
|
@ -850,7 +821,7 @@ xpath_choice(cxobj *xcur,
|
||||||
size_t *vec1len)
|
size_t *vec1len)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
char *s0;
|
char *s0 = NULL;
|
||||||
char *s1;
|
char *s1;
|
||||||
char *s2;
|
char *s2;
|
||||||
char *xpath;
|
char *xpath;
|
||||||
|
|
@ -858,7 +829,7 @@ xpath_choice(cxobj *xcur,
|
||||||
size_t vec0len = 0;
|
size_t vec0len = 0;
|
||||||
|
|
||||||
if ((s0 = strdup(xpath0)) == NULL){
|
if ((s0 = strdup(xpath0)) == NULL){
|
||||||
clicon_err(OE_XML, errno, "%s: strdup", __FUNCTION__);
|
clicon_err(OE_XML, errno, "strdup");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
s2 = s1 = s0;
|
s2 = s1 = s0;
|
||||||
|
|
@ -880,7 +851,7 @@ xpath_choice(cxobj *xcur,
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
if (s0)
|
if (s0)
|
||||||
free(s0);
|
free(s0);
|
||||||
if (vec0)
|
if (vec0)
|
||||||
|
|
@ -888,11 +859,26 @@ xpath_choice(cxobj *xcur,
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Help function to xpath_first
|
/*! Xpath nodeset function where only the first matching entry is returned
|
||||||
|
* args:
|
||||||
|
* @param[in] xcur xml-tree where to search
|
||||||
|
* @param[in] xpath string with XPATH syntax
|
||||||
|
* @retval xml-tree of first match
|
||||||
|
* @retval NULL Error or not found
|
||||||
|
*
|
||||||
|
* @code
|
||||||
|
* cxobj *x;
|
||||||
|
* if ((x = xpath_first(xtop, "//symbol/foo")) != NULL) {
|
||||||
|
* ...
|
||||||
|
* }
|
||||||
|
* @endcode
|
||||||
|
* @note the returned pointer points into the original tree so should not be freed fter use.
|
||||||
|
* @note return value does not see difference between error and not found
|
||||||
|
* @see xpath_first. This is obsolete and only enabled with COMPAT_XSL
|
||||||
*/
|
*/
|
||||||
static cxobj *
|
cxobj *
|
||||||
xpath_first0(cxobj *xcur,
|
xpath_first_xsl(cxobj *xcur,
|
||||||
char *xpath)
|
char *xpath)
|
||||||
{
|
{
|
||||||
cxobj **vec1 = NULL;
|
cxobj **vec1 = NULL;
|
||||||
size_t vec1len = 0;
|
size_t vec1len = 0;
|
||||||
|
|
@ -910,57 +896,7 @@ xpath_first0(cxobj *xcur,
|
||||||
return xn;
|
return xn;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! A restricted xpath function where the first matching entry is returned
|
#ifdef COMPAT_XSL
|
||||||
* See xpath1() on details for subset.
|
|
||||||
* args:
|
|
||||||
* @param[in] xcur xml-tree where to search
|
|
||||||
* @param[in] xpath string with XPATH syntax
|
|
||||||
* @retval xml-tree of first match
|
|
||||||
* @retval NULL Error or not found
|
|
||||||
*
|
|
||||||
* @code
|
|
||||||
* cxobj *x;
|
|
||||||
* if ((x = xpath_first(xtop, "//symbol/foo")) != NULL) {
|
|
||||||
* ...
|
|
||||||
* }
|
|
||||||
* @endcode
|
|
||||||
* @note the returned pointer points into the original tree so should not be freed after use.
|
|
||||||
* @note return value does not see difference between error and not found
|
|
||||||
* @see also xpath_vec.
|
|
||||||
*/
|
|
||||||
cxobj *
|
|
||||||
xpath_first(cxobj *xcur,
|
|
||||||
char *format,
|
|
||||||
...)
|
|
||||||
{
|
|
||||||
cxobj *retval = NULL;
|
|
||||||
va_list ap;
|
|
||||||
size_t len;
|
|
||||||
char *xpath;
|
|
||||||
|
|
||||||
va_start(ap, format);
|
|
||||||
len = vsnprintf(NULL, 0, format, ap);
|
|
||||||
va_end(ap);
|
|
||||||
/* allocate a message string exactly fitting the message length */
|
|
||||||
if ((xpath = malloc(len+1)) == NULL){
|
|
||||||
clicon_err(OE_UNIX, errno, "malloc");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
/* second round: compute write message from reason and args */
|
|
||||||
va_start(ap, format);
|
|
||||||
if (vsnprintf(xpath, len+1, format, ap) < 0){
|
|
||||||
clicon_err(OE_UNIX, errno, "vsnprintf");
|
|
||||||
va_end(ap);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
va_end(ap);
|
|
||||||
retval = xpath_first0(xcur, xpath);
|
|
||||||
done:
|
|
||||||
if (xpath)
|
|
||||||
free(xpath);
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! A restricted xpath iterator that loops over all matching entries. Dont use.
|
/*! A restricted xpath iterator that loops over all matching entries. Dont use.
|
||||||
*
|
*
|
||||||
* See xpath1() on details for subset.
|
* See xpath1() on details for subset.
|
||||||
|
|
@ -976,10 +912,9 @@ xpath_first(cxobj *xcur,
|
||||||
* }
|
* }
|
||||||
* @endcode
|
* @endcode
|
||||||
*
|
*
|
||||||
* Note that the returned pointer points into the original tree so should not be freed
|
* @note The returned pointer points into the original tree so should not be freed
|
||||||
* after use.
|
* after use.
|
||||||
* @see also xpath, xpath_vec.
|
* @note obsolete. Dont use
|
||||||
* NOTE: uses a static variable: consider replacing with xpath_vec() instead
|
|
||||||
*/
|
*/
|
||||||
cxobj *
|
cxobj *
|
||||||
xpath_each(cxobj *xcur,
|
xpath_each(cxobj *xcur,
|
||||||
|
|
@ -1018,11 +953,12 @@ xpath_each(cxobj *xcur,
|
||||||
done:
|
done:
|
||||||
return xn;
|
return xn;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/*! A restricted xpath that returns a vector of matches
|
/*! A restricted xpath that returns a vector of matches
|
||||||
*
|
*
|
||||||
* See xpath1() on details for subset
|
* See xpath1() on details for subset
|
||||||
. * @param[in] xcur xml-tree where to search
|
* @param[in] xcur xml-tree where to search
|
||||||
* @param[in] xpath string with XPATH syntax
|
* @param[in] xpath string with XPATH syntax
|
||||||
* @param[out] vec vector of xml-trees. Vector must be free():d after use
|
* @param[out] vec vector of xml-trees. Vector must be free():d after use
|
||||||
* @param[out] veclen returns length of vector in return value
|
* @param[out] veclen returns length of vector in return value
|
||||||
|
|
@ -1043,41 +979,22 @@ xpath_each(cxobj *xcur,
|
||||||
* @note Although the returned vector must be freed after use,
|
* @note Although the returned vector must be freed after use,
|
||||||
* the returned xml trees should not.
|
* the returned xml trees should not.
|
||||||
* @see also xpath_first, xpath_each.
|
* @see also xpath_first, xpath_each.
|
||||||
|
* @see xpath_vec. This is obsolete and only enabled with COMPAT_XSL
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
xpath_vec(cxobj *xcur,
|
xpath_vec_xsl(cxobj *xcur,
|
||||||
char *format,
|
char *xpath,
|
||||||
cxobj ***vec,
|
cxobj ***vec,
|
||||||
size_t *veclen,
|
size_t *veclen)
|
||||||
...)
|
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
va_list ap;
|
|
||||||
size_t len;
|
|
||||||
char *xpath;
|
|
||||||
|
|
||||||
va_start(ap, veclen);
|
|
||||||
len = vsnprintf(NULL, 0, format, ap);
|
|
||||||
va_end(ap);
|
|
||||||
/* allocate a message string exactly fitting the message length */
|
|
||||||
if ((xpath = malloc(len+1)) == NULL){
|
|
||||||
clicon_err(OE_UNIX, errno, "malloc");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
/* second round: compute write message from reason and args */
|
|
||||||
va_start(ap, veclen);
|
|
||||||
if (vsnprintf(xpath, len+1, format, ap) < 0){
|
|
||||||
clicon_err(OE_UNIX, errno, "vsnprintf");
|
|
||||||
va_end(ap);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
va_end(ap);
|
|
||||||
*vec = NULL;
|
*vec = NULL;
|
||||||
*veclen = 0;
|
*veclen = 0;
|
||||||
retval = xpath_choice(xcur, xpath, 0x0, vec, veclen);
|
if (xpath_choice(xcur, xpath, 0x0, vec, veclen) < 0)
|
||||||
|
goto done;
|
||||||
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
if (xpath)
|
|
||||||
free(xpath);
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1102,99 +1019,23 @@ xpath_vec(cxobj *xcur,
|
||||||
* @endcode
|
* @endcode
|
||||||
* @Note that although the returned vector must be freed after use, the returned xml
|
* @Note that although the returned vector must be freed after use, the returned xml
|
||||||
* trees need not be.
|
* trees need not be.
|
||||||
* @see also xpath_vec This is a specialized version.
|
* @see xpath_vec_flag. This is obsolete and only enabled with COMPAT_XSL
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
xpath_vec_flag(cxobj *xcur,
|
xpath_vec_flag_xsl(cxobj *xcur,
|
||||||
char *format,
|
char *xpath,
|
||||||
uint16_t flags,
|
uint16_t flags,
|
||||||
cxobj ***vec,
|
cxobj ***vec,
|
||||||
size_t *veclen,
|
size_t *veclen)
|
||||||
...)
|
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
va_list ap;
|
|
||||||
size_t len;
|
|
||||||
char *xpath;
|
|
||||||
|
|
||||||
va_start(ap, veclen);
|
|
||||||
len = vsnprintf(NULL, 0, format, ap);
|
|
||||||
va_end(ap);
|
|
||||||
/* allocate a message string exactly fitting the message length */
|
|
||||||
if ((xpath = malloc(len+1)) == NULL){
|
|
||||||
clicon_err(OE_UNIX, errno, "malloc");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
/* second round: compute write message from reason and args */
|
|
||||||
va_start(ap, veclen);
|
|
||||||
if (vsnprintf(xpath, len+1, format, ap) < 0){
|
|
||||||
clicon_err(OE_UNIX, errno, "vsnprintf");
|
|
||||||
va_end(ap);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
va_end(ap);
|
|
||||||
*vec=NULL;
|
*vec=NULL;
|
||||||
*veclen = 0;
|
*veclen = 0;
|
||||||
retval = xpath_choice(xcur, xpath, flags, vec, veclen);
|
if (xpath_choice(xcur, xpath, flags, vec, veclen) < 0)
|
||||||
|
goto done;
|
||||||
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
if (xpath)
|
|
||||||
free(xpath);
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Turn this on to get an xpath test program
|
|
||||||
* Usage: xpath [<xpath>]
|
|
||||||
* read xml from input
|
|
||||||
* Example compile:
|
|
||||||
gcc -g -o xpath -I. -I../clixon ./clixon_xsl.c -lclixon -lcligen
|
|
||||||
* Example run:
|
|
||||||
echo "<a><b/></a>" | xpath "a"
|
|
||||||
*/
|
|
||||||
#if 0 /* Test program */
|
|
||||||
|
|
||||||
|
|
||||||
static int
|
|
||||||
usage(char *argv0)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "usage:%s <xpath>.\n\tInput on stdin\n", argv0);
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
main(int argc, char **argv)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
cxobj **xv
|
|
||||||
cxobj *x;
|
|
||||||
cxobj *xn;
|
|
||||||
size_t xlen = 0;
|
|
||||||
|
|
||||||
if (argc != 2){
|
|
||||||
usage(argv[0]);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (xml_parse_file(0, &x, "</clicon>") < 0){
|
|
||||||
fprintf(stderr, "parsing 2\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
printf("\n");
|
|
||||||
|
|
||||||
if (xpath_vec(x, argv[1], &xv, &xlen) < 0)
|
|
||||||
return -1;
|
|
||||||
if (xv){
|
|
||||||
for (i=0; i<xlen; i++){
|
|
||||||
xn = xv[i];
|
|
||||||
fprintf(stdout, "[%d]:\n", i);
|
|
||||||
clicon_xml2file(stdout, xn, 0, 1);
|
|
||||||
}
|
|
||||||
free(xv);
|
|
||||||
}
|
|
||||||
if (x)
|
|
||||||
xml_free(x);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* Test program */
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -45,11 +45,14 @@
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
#include <unistd.h>
|
||||||
#define __USE_GNU /* strverscmp */
|
#define __USE_GNU /* strverscmp */
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#include <regex.h>
|
#include <regex.h>
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <fcntl.h>
|
||||||
#include <syslog.h>
|
#include <syslog.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
|
@ -74,6 +77,8 @@
|
||||||
#include "clixon_yang_type.h"
|
#include "clixon_yang_type.h"
|
||||||
#include "clixon_yang_parse.h"
|
#include "clixon_yang_parse.h"
|
||||||
|
|
||||||
|
/* Size of json read buffer when reading from file*/
|
||||||
|
#define BUFLEN 1024
|
||||||
|
|
||||||
/* Mapping between yang keyword string <--> clicon constants */
|
/* Mapping between yang keyword string <--> clicon constants */
|
||||||
static const map_str2int ykmap[] = {
|
static const map_str2int ykmap[] = {
|
||||||
|
|
@ -158,7 +163,7 @@ yspec_new(void)
|
||||||
yang_spec *yspec;
|
yang_spec *yspec;
|
||||||
|
|
||||||
if ((yspec = malloc(sizeof(*yspec))) == NULL){
|
if ((yspec = malloc(sizeof(*yspec))) == NULL){
|
||||||
clicon_err(OE_YANG, errno, "%s: malloc", __FUNCTION__);
|
clicon_err(OE_YANG, errno, "malloc");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
memset(yspec, 0, sizeof(*yspec));
|
memset(yspec, 0, sizeof(*yspec));
|
||||||
|
|
@ -176,7 +181,7 @@ ys_new(enum rfc_6020 keyw)
|
||||||
yang_stmt *ys;
|
yang_stmt *ys;
|
||||||
|
|
||||||
if ((ys = malloc(sizeof(*ys))) == NULL){
|
if ((ys = malloc(sizeof(*ys))) == NULL){
|
||||||
clicon_err(OE_YANG, errno, "%s: malloc", __FUNCTION__);
|
clicon_err(OE_YANG, errno, "malloc");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
memset(ys, 0, sizeof(*ys));
|
memset(ys, 0, sizeof(*ys));
|
||||||
|
|
@ -184,7 +189,7 @@ ys_new(enum rfc_6020 keyw)
|
||||||
/* The cvec contains stmt-specific variables. Only few stmts need variables so the
|
/* The cvec contains stmt-specific variables. Only few stmts need variables so the
|
||||||
cvec could be lazily created to save some heap and cycles. */
|
cvec could be lazily created to save some heap and cycles. */
|
||||||
if ((ys->ys_cvec = cvec_new(0)) == NULL){
|
if ((ys->ys_cvec = cvec_new(0)) == NULL){
|
||||||
clicon_err(OE_YANG, errno, "%s: cvec_new", __FUNCTION__);
|
clicon_err(OE_YANG, errno, "cvec_new");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
return ys;
|
return ys;
|
||||||
|
|
@ -247,7 +252,7 @@ yn_realloc(yang_node *yn)
|
||||||
yn->yn_len++;
|
yn->yn_len++;
|
||||||
|
|
||||||
if ((yn->yn_stmt = realloc(yn->yn_stmt, (yn->yn_len)*sizeof(yang_stmt *))) == 0){
|
if ((yn->yn_stmt = realloc(yn->yn_stmt, (yn->yn_len)*sizeof(yang_stmt *))) == 0){
|
||||||
clicon_err(OE_YANG, errno, "%s: realloc", __FUNCTION__);
|
clicon_err(OE_YANG, errno, "realloc");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
yn->yn_stmt[yn->yn_len - 1] = NULL; /* init field */
|
yn->yn_stmt[yn->yn_len - 1] = NULL; /* init field */
|
||||||
|
|
@ -255,6 +260,13 @@ yn_realloc(yang_node *yn)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Copy yang statement recursively from old to new
|
/*! Copy yang statement recursively from old to new
|
||||||
|
* @param[in] ynew New empty (but created) yang statement (to)
|
||||||
|
* @param[in] yold Old existing yang statement (from)
|
||||||
|
* @code
|
||||||
|
* yang_stmt *new = ys_new(Y_LEAF);
|
||||||
|
* if (ys_cp(new, old) < 0)
|
||||||
|
* err;
|
||||||
|
* @endcode
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
ys_cp(yang_stmt *ynew,
|
ys_cp(yang_stmt *ynew,
|
||||||
|
|
@ -269,22 +281,22 @@ ys_cp(yang_stmt *ynew,
|
||||||
ynew->ys_parent = NULL;
|
ynew->ys_parent = NULL;
|
||||||
if (yold->ys_stmt)
|
if (yold->ys_stmt)
|
||||||
if ((ynew->ys_stmt = calloc(yold->ys_len, sizeof(yang_stmt *))) == NULL){
|
if ((ynew->ys_stmt = calloc(yold->ys_len, sizeof(yang_stmt *))) == NULL){
|
||||||
clicon_err(OE_YANG, errno, "%s: calloc", __FUNCTION__);
|
clicon_err(OE_YANG, errno, "calloc");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (yold->ys_argument)
|
if (yold->ys_argument)
|
||||||
if ((ynew->ys_argument = strdup(yold->ys_argument)) == NULL){
|
if ((ynew->ys_argument = strdup(yold->ys_argument)) == NULL){
|
||||||
clicon_err(OE_YANG, errno, "%s: strdup", __FUNCTION__);
|
clicon_err(OE_YANG, errno, "strdup");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (yold->ys_cv)
|
if (yold->ys_cv)
|
||||||
if ((ynew->ys_cv = cv_dup(yold->ys_cv)) == NULL){
|
if ((ynew->ys_cv = cv_dup(yold->ys_cv)) == NULL){
|
||||||
clicon_err(OE_YANG, errno, "%s: cv_dup", __FUNCTION__);
|
clicon_err(OE_YANG, errno, "cv_dup");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (yold->ys_cvec)
|
if (yold->ys_cvec)
|
||||||
if ((ynew->ys_cvec = cvec_dup(yold->ys_cvec)) == NULL){
|
if ((ynew->ys_cvec = cvec_dup(yold->ys_cvec)) == NULL){
|
||||||
clicon_err(OE_YANG, errno, "%s: cvec_dup", __FUNCTION__);
|
clicon_err(OE_YANG, errno, "cvec_dup");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (yold->ys_typecache){
|
if (yold->ys_typecache){
|
||||||
|
|
@ -304,8 +316,10 @@ ys_cp(yang_stmt *ynew,
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Create a new yang node and copy the contents recursively from the original.
|
/*! Create a new yang node and copy the contents recursively from the original. *
|
||||||
*
|
* @param[in] old Old existing yang statement (from)
|
||||||
|
* @retval NULL Error
|
||||||
|
* @retval new New created yang statement
|
||||||
* This may involve duplicating strings, etc.
|
* This may involve duplicating strings, etc.
|
||||||
* The new yang tree needs to be freed by ys_free().
|
* The new yang tree needs to be freed by ys_free().
|
||||||
* The parent of new is NULL, it needs to be explicityl inserted somewhere
|
* The parent of new is NULL, it needs to be explicityl inserted somewhere
|
||||||
|
|
@ -328,7 +342,6 @@ ys_dup(yang_stmt *old)
|
||||||
return new;
|
return new;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*! Insert yang statement as child of a parent yang_statement, last in list
|
/*! Insert yang statement as child of a parent yang_statement, last in list
|
||||||
*
|
*
|
||||||
* Also add parent to child as up-pointer
|
* Also add parent to child as up-pointer
|
||||||
|
|
@ -598,8 +611,8 @@ yang_find_schemanode(yang_node *yn,
|
||||||
/*! Find first matching data node in all (sub)modules in a yang spec
|
/*! Find first matching data node in all (sub)modules in a yang spec
|
||||||
*
|
*
|
||||||
* @param[in] ysp Yang specification
|
* @param[in] ysp Yang specification
|
||||||
* @param[in] argument if NULL, match any(first) argument. XXX is that really a case?
|
* @param[in] argument Name of node. If NULL match first
|
||||||
* @param[in] schemanode If set look for schema nodes, otherwise only data nodes
|
* @param[in] class See yang_class for class of yang nodes
|
||||||
* A yang specification has modules as children which in turn can have
|
* A yang specification has modules as children which in turn can have
|
||||||
* syntax-nodes as children. This function goes through all the modules to
|
* syntax-nodes as children. This function goes through all the modules to
|
||||||
* look for nodes. Note that if a child to a module is a choice,
|
* look for nodes. Note that if a child to a module is a choice,
|
||||||
|
|
@ -790,7 +803,7 @@ yarg_id(yang_stmt *ys)
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Assume argument is id on the type: <[prefix:]id>, return 'prefix'
|
/*! Assume argument is id on the type: <[prefix:]id>, return 'prefix'
|
||||||
* @param[in] ys A yang statement
|
* @param[in] ys A yang statement
|
||||||
* @retval NULL No prefix
|
* @retval NULL No prefix
|
||||||
* @retval prefix Malloced string that needs to be freed by caller.
|
* @retval prefix Malloced string that needs to be freed by caller.
|
||||||
|
|
@ -810,6 +823,44 @@ yarg_prefix(yang_stmt *ys)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*! Split yang node identifier into prefix and identifer.
|
||||||
|
* @param[in] node-id
|
||||||
|
* @param[out] prefix Malloced string. May be NULL.
|
||||||
|
* @param[out] id Malloced identifier.
|
||||||
|
* @retval 0 OK
|
||||||
|
* @retval -1 Error
|
||||||
|
* @note caller need to free id and prefix after use
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
yang_nodeid_split(char *nodeid,
|
||||||
|
char **prefix,
|
||||||
|
char **id)
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
char *str;
|
||||||
|
|
||||||
|
if ((str = strchr(nodeid, ':')) == NULL){
|
||||||
|
if ((*id = strdup(nodeid)) == NULL){
|
||||||
|
clicon_err(OE_YANG, errno, "strdup");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
if ((*prefix = strdup(nodeid)) == NULL){
|
||||||
|
clicon_err(OE_YANG, errno, "strdup");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
(*prefix)[str-nodeid] = '\0';
|
||||||
|
str++;
|
||||||
|
if ((*id = strdup(str)) == NULL){
|
||||||
|
clicon_err(OE_YANG, errno, "strdup");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
retval = 0;
|
||||||
|
done:
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
/*! Given a yang statement and a prefix, return yang module to that prefix
|
/*! Given a yang statement and a prefix, return yang module to that prefix
|
||||||
* Note, not the other module but the proxy import statement only
|
* Note, not the other module but the proxy import statement only
|
||||||
|
|
@ -896,7 +947,7 @@ yang_print(FILE *f,
|
||||||
cbuf *cb = NULL;
|
cbuf *cb = NULL;
|
||||||
|
|
||||||
if ((cb = cbuf_new()) == NULL){
|
if ((cb = cbuf_new()) == NULL){
|
||||||
clicon_err(OE_YANG, errno, "%s: cbuf_new", __FUNCTION__);
|
clicon_err(OE_YANG, errno, "cbuf_new");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (yang_print_cbuf(cb, yn, 0) < 0)
|
if (yang_print_cbuf(cb, yn, 0) < 0)
|
||||||
|
|
@ -992,14 +1043,14 @@ ys_populate_leaf(yang_stmt *ys,
|
||||||
goto done;
|
goto done;
|
||||||
/* 2. Create the CV using cvtype and name it */
|
/* 2. Create the CV using cvtype and name it */
|
||||||
if ((cv = cv_new(cvtype)) == NULL){
|
if ((cv = cv_new(cvtype)) == NULL){
|
||||||
clicon_err(OE_YANG, errno, "%s: cv_new", __FUNCTION__);
|
clicon_err(OE_YANG, errno, "cv_new");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (options & YANG_OPTIONS_FRACTION_DIGITS && cvtype == CGV_DEC64) /* XXX: Seems misplaced? / too specific */
|
if (options & YANG_OPTIONS_FRACTION_DIGITS && cvtype == CGV_DEC64) /* XXX: Seems misplaced? / too specific */
|
||||||
cv_dec64_n_set(cv, fraction_digits);
|
cv_dec64_n_set(cv, fraction_digits);
|
||||||
|
|
||||||
if (cv_name_set(cv, ys->ys_argument) == NULL){
|
if (cv_name_set(cv, ys->ys_argument) == NULL){
|
||||||
clicon_err(OE_YANG, errno, "%s: cv_new_set", __FUNCTION__);
|
clicon_err(OE_YANG, errno, "cv_new_set");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
/* 3. Check if default value. Here we parse the string in the default-stmt
|
/* 3. Check if default value. Here we parse the string in the default-stmt
|
||||||
|
|
@ -1077,7 +1128,7 @@ ys_populate_range(yang_stmt *ys,
|
||||||
|
|
||||||
yparent = ys->ys_parent; /* Find parent: type */
|
yparent = ys->ys_parent; /* Find parent: type */
|
||||||
if (yparent->yn_keyword != Y_TYPE){
|
if (yparent->yn_keyword != Y_TYPE){
|
||||||
clicon_err(OE_YANG, 0, "%s: parent should be type", __FUNCTION__);
|
clicon_err(OE_YANG, 0, "parent should be type");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (yang_type_resolve(ys, (yang_stmt*)yparent, &yrestype,
|
if (yang_type_resolve(ys, (yang_stmt*)yparent, &yrestype,
|
||||||
|
|
@ -1097,7 +1148,8 @@ ys_populate_range(yang_stmt *ys,
|
||||||
}
|
}
|
||||||
if ((maxstr = strstr(minstr, "..")) != NULL){
|
if ((maxstr = strstr(minstr, "..")) != NULL){
|
||||||
if (strlen(maxstr) < 2){
|
if (strlen(maxstr) < 2){
|
||||||
clicon_err(OE_YANG, 0, "range statement: %s not on the form: <int>..<int>");
|
clicon_err(OE_YANG, 0, "range statement: %s not on the form: <int>..<int>",
|
||||||
|
ys->ys_argument);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
minstr[maxstr-minstr] = '\0';
|
minstr[maxstr-minstr] = '\0';
|
||||||
|
|
@ -1160,6 +1212,8 @@ ys_populate_range(yang_stmt *ys,
|
||||||
|
|
||||||
/*! Sanity check yang type statement
|
/*! Sanity check yang type statement
|
||||||
* XXX: Replace with generic parent/child type-check
|
* XXX: Replace with generic parent/child type-check
|
||||||
|
* @param[in] ys The yang statement (type) to populate.
|
||||||
|
* @
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
ys_populate_type(yang_stmt *ys,
|
ys_populate_type(yang_stmt *ys,
|
||||||
|
|
@ -1191,28 +1245,86 @@ ys_populate_type(yang_stmt *ys,
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Sanity check yang type statement
|
/*! Sanity check yang identity statement recursively
|
||||||
|
*
|
||||||
|
* Find base identities if any and add this identity to derived list.
|
||||||
|
* Do this recursively
|
||||||
|
* @param[in] ys The yang identity to populate.
|
||||||
|
* @param[in] arg If set contains a derived identifier
|
||||||
|
* @see validate_identityref which in runtime validates actual valoues
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
ys_populate_identity(yang_stmt *ys,
|
ys_populate_identity(yang_stmt *ys,
|
||||||
void *arg)
|
void *arg)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
yang_stmt *ybase;
|
yang_stmt *yc = NULL;
|
||||||
|
yang_stmt *ybaseid;
|
||||||
|
cg_var *cv;
|
||||||
|
char *derid;
|
||||||
|
char *baseid;
|
||||||
|
char *prefix = NULL;
|
||||||
|
cbuf *cb = NULL;
|
||||||
|
char *idref = (char*)arg;
|
||||||
|
char *p;
|
||||||
|
|
||||||
if ((ybase = yang_find((yang_node*)ys, Y_BASE, NULL)) == NULL)
|
if (idref == NULL){
|
||||||
return 0;
|
/* Create derived identity through prefix:id if not recursively called*/
|
||||||
if ((yang_find_identity(ys, ybase->ys_argument)) == NULL){
|
derid = ys->ys_argument; /* derived id */
|
||||||
clicon_err(OE_YANG, 0, "Identity %s not found (base type of %s)",
|
if ((prefix = yarg_prefix(ys)) == NULL){
|
||||||
ybase->ys_argument, ys->ys_argument);
|
if ((p = yang_find_myprefix(ys)) != NULL)
|
||||||
goto done;
|
prefix = strdup(yang_find_myprefix(ys));
|
||||||
|
}
|
||||||
|
if ((cb = cbuf_new()) == NULL){
|
||||||
|
clicon_err(OE_UNIX, errno, "cbuf_new");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if (prefix)
|
||||||
|
cprintf(cb, "%s:%s", prefix, derid);
|
||||||
|
else
|
||||||
|
cprintf(cb, "%s", derid);
|
||||||
|
idref = cbuf_get(cb);
|
||||||
|
}
|
||||||
|
/* Iterate through all base statements and check the base identity exists
|
||||||
|
* AND populate the base identity recursively
|
||||||
|
*/
|
||||||
|
while ((yc = yn_each((yang_node*)ys, yc)) != NULL) {
|
||||||
|
if (yc->ys_keyword != Y_BASE)
|
||||||
|
continue;
|
||||||
|
baseid = yc->ys_argument;
|
||||||
|
if (((ybaseid = yang_find_identity(ys, baseid))) == NULL){
|
||||||
|
clicon_err(OE_YANG, 0, "No such identity: %s", baseid);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
// continue; /* root identity */
|
||||||
|
/* Check if derived id is already in base identifier */
|
||||||
|
if (cvec_find(ybaseid->ys_cvec, idref) != NULL)
|
||||||
|
continue;
|
||||||
|
/* Add derived id to ybaseid */
|
||||||
|
if ((cv = cv_new(CGV_STRING)) == NULL){
|
||||||
|
clicon_err(OE_UNIX, errno, "cv_new");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
/* add prefix */
|
||||||
|
cv_name_set(cv, idref);
|
||||||
|
cvec_append_var(ybaseid->ys_cvec, cv); /* cv copied */
|
||||||
|
if (cv){
|
||||||
|
cv_free(cv);
|
||||||
|
cv = NULL;
|
||||||
|
}
|
||||||
|
/* Transitive to the root */
|
||||||
|
if (ys_populate_identity(ybaseid, idref) < 0)
|
||||||
|
goto done;
|
||||||
}
|
}
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
|
if (prefix)
|
||||||
|
free(prefix);
|
||||||
|
if (cb)
|
||||||
|
cbuf_free(cb);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*! Populate with cligen-variables, default values, etc. Sanity checks on complete tree.
|
/*! Populate with cligen-variables, default values, etc. Sanity checks on complete tree.
|
||||||
*
|
*
|
||||||
* We do this in 2nd pass after complete parsing to be sure to have a complete parse-tree
|
* We do this in 2nd pass after complete parsing to be sure to have a complete parse-tree
|
||||||
|
|
@ -1433,7 +1545,7 @@ yang_expand(yang_node *yn)
|
||||||
size = (yn->yn_len - i - 1)*sizeof(struct yang_stmt *);
|
size = (yn->yn_len - i - 1)*sizeof(struct yang_stmt *);
|
||||||
yn->yn_len += glen - 1;
|
yn->yn_len += glen - 1;
|
||||||
if (glen && (yn->yn_stmt = realloc(yn->yn_stmt, (yn->yn_len)*sizeof(yang_stmt *))) == 0){
|
if (glen && (yn->yn_stmt = realloc(yn->yn_stmt, (yn->yn_len)*sizeof(yang_stmt *))) == 0){
|
||||||
clicon_err(OE_YANG, errno, "%s: realloc", __FUNCTION__);
|
clicon_err(OE_YANG, errno, "realloc");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
/* Then move all existing elements up from i+1 (not uses-stmt) */
|
/* Then move all existing elements up from i+1 (not uses-stmt) */
|
||||||
|
|
@ -1474,10 +1586,10 @@ yang_expand(yang_node *yn)
|
||||||
* Syntax parsing. A string is input and a syntax-tree is returned (or error).
|
* Syntax parsing. A string is input and a syntax-tree is returned (or error).
|
||||||
* A variable record is also returned containing a list of (global) variable values.
|
* A variable record is also returned containing a list of (global) variable values.
|
||||||
* (cloned from cligen)
|
* (cloned from cligen)
|
||||||
* @param h CLICON handle
|
* @param[in] h CLICON handle
|
||||||
* @param str String of yang statements
|
* @param[in] str String of yang statements
|
||||||
* @param name Log string, typically filename
|
* @param[in] name Log string, typically filename
|
||||||
* @param ysp Yang specification. Should ave been created by caller using yspec_new
|
* @param[in] ysp Yang specification. Should ave been created by caller using yspec_new
|
||||||
* @retval ymod Top-level yang (sub)module
|
* @retval ymod Top-level yang (sub)module
|
||||||
* @retval NULL Error encountered
|
* @retval NULL Error encountered
|
||||||
* Calling order:
|
* Calling order:
|
||||||
|
|
@ -1488,21 +1600,22 @@ yang_expand(yang_node *yn)
|
||||||
* clixon_yang_parseparse # Actual yang parsing using yacc
|
* clixon_yang_parseparse # Actual yang parsing using yacc
|
||||||
*/
|
*/
|
||||||
static yang_stmt *
|
static yang_stmt *
|
||||||
yang_parse_str(clicon_handle h,
|
yang_parse_str(char *str,
|
||||||
char *str,
|
|
||||||
const char *name, /* just for errs */
|
const char *name, /* just for errs */
|
||||||
yang_spec *yspec)
|
yang_spec *yspec)
|
||||||
{
|
{
|
||||||
struct clicon_yang_yacc_arg yy = {0,};
|
struct clicon_yang_yacc_arg yy = {0,};
|
||||||
yang_stmt *ymod = NULL;
|
yang_stmt *ymod = NULL;
|
||||||
|
|
||||||
yy.yy_handle = h;
|
if (yspec == NULL){
|
||||||
|
clicon_err(OE_YANG, 0, "Yang parse need top level yang spec");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
yy.yy_name = (char*)name;
|
yy.yy_name = (char*)name;
|
||||||
yy.yy_linenum = 1;
|
yy.yy_linenum = 1;
|
||||||
yy.yy_parse_string = str;
|
yy.yy_parse_string = str;
|
||||||
yy.yy_stack = NULL;
|
yy.yy_stack = NULL;
|
||||||
yy.yy_module = NULL; /* this is the return value - the module/sub-module */
|
yy.yy_module = NULL; /* this is the return value - the module/sub-module */
|
||||||
|
|
||||||
if (ystack_push(&yy, (yang_node*)yspec) == NULL)
|
if (ystack_push(&yy, (yang_node*)yspec) == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
if (strlen(str)){ /* Not empty */
|
if (strlen(str)){ /* Not empty */
|
||||||
|
|
@ -1526,18 +1639,71 @@ yang_parse_str(clicon_handle h,
|
||||||
ymod = yy.yy_module;
|
ymod = yy.yy_module;
|
||||||
done:
|
done:
|
||||||
ystack_pop(&yy);
|
ystack_pop(&yy);
|
||||||
|
if (yy.yy_stack)
|
||||||
|
free (yy.yy_stack);
|
||||||
return ymod; /* top-level (sub)module */
|
return ymod; /* top-level (sub)module */
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Read an opened file into a string and call yang string parsing
|
/*! Parse yang spec from an open file descriptor
|
||||||
|
* @param[in] fd File descriptor containing the YANG file as ASCII characters
|
||||||
|
* @param[in] name For debug, eg filename
|
||||||
|
* @param[in] ysp Yang specification. Should ave been created by caller using yspec_new
|
||||||
|
* @retval ymod Top-level yang (sub)module
|
||||||
|
* @retval NULL Error
|
||||||
|
*/
|
||||||
|
yang_stmt *
|
||||||
|
yang_parse_file(int fd,
|
||||||
|
const char *name,
|
||||||
|
yang_spec *ysp)
|
||||||
|
{
|
||||||
|
char *buf = NULL;
|
||||||
|
int i;
|
||||||
|
int c;
|
||||||
|
int len;
|
||||||
|
yang_stmt *ymod = NULL;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
len = BUFLEN; /* any number is fine */
|
||||||
|
if ((buf = malloc(len)) == NULL){
|
||||||
|
perror("pt_file malloc");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
memset(buf, 0, len);
|
||||||
|
i = 0; /* position in buf */
|
||||||
|
while (1){ /* read the whole file */
|
||||||
|
if ((ret = read(fd, &c, 1)) < 0){
|
||||||
|
clicon_err(OE_XML, errno, "read");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (ret == 0)
|
||||||
|
break; /* eof */
|
||||||
|
if (len==i){
|
||||||
|
if ((buf = realloc(buf, 2*len)) == NULL){
|
||||||
|
clicon_err(OE_XML, errno, "realloc");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
memset(buf+len, 0, len);
|
||||||
|
len *= 2;
|
||||||
|
}
|
||||||
|
buf[i++] = (char)(c&0xff);
|
||||||
|
} /* read a line */
|
||||||
|
if ((ymod = yang_parse_str(buf, name, ysp)) < 0)
|
||||||
|
goto done;
|
||||||
|
done:
|
||||||
|
if (buf)
|
||||||
|
free(buf);
|
||||||
|
return ymod; /* top-level (sub)module */
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Open a file, read into a string and invoke yang parsing
|
||||||
*
|
*
|
||||||
* Similar to clicon_yang_str(), just read a file first
|
* Similar to clicon_yang_str(), just read a file first
|
||||||
* (cloned from cligen)
|
* (cloned from cligen)
|
||||||
* @param h CLICON handle
|
* @param[in] h CLICON handle
|
||||||
* @param filename Name of file
|
* @param[in] filename Name of file
|
||||||
* @param ysp Yang specification. Should ave been created by caller using yspec_new
|
* @param[in] ysp Yang specification. Should ave been created by caller using yspec_new
|
||||||
* @retval ymod Top-level yang (sub)module
|
* @retval ymod Top-level yang (sub)module
|
||||||
* @retval NULL Error encountered
|
* @retval NULL Error encountered
|
||||||
|
|
||||||
* The database symbols are inserted in alphabetical order.
|
* The database symbols are inserted in alphabetical order.
|
||||||
* Calling order:
|
* Calling order:
|
||||||
|
|
@ -1548,57 +1714,27 @@ yang_parse_str(clicon_handle h,
|
||||||
* clixon_yang_parseparse # Actual yang parsing using yacc
|
* clixon_yang_parseparse # Actual yang parsing using yacc
|
||||||
*/
|
*/
|
||||||
static yang_stmt *
|
static yang_stmt *
|
||||||
yang_parse_file(clicon_handle h,
|
yang_parse_filename(const char *filename,
|
||||||
const char *filename,
|
yang_spec *ysp)
|
||||||
yang_spec *ysp
|
|
||||||
)
|
|
||||||
{
|
{
|
||||||
char *buf = NULL;
|
|
||||||
int i;
|
|
||||||
int c;
|
|
||||||
int len;
|
|
||||||
yang_stmt *ymod = NULL;
|
yang_stmt *ymod = NULL;
|
||||||
FILE *f = NULL;
|
int fd = -1;
|
||||||
struct stat st;
|
struct stat st;
|
||||||
|
|
||||||
clicon_log(LOG_DEBUG, "Parsing yang file: %s", filename);
|
clicon_log(LOG_DEBUG, "Parsing yang file: %s", filename);
|
||||||
if (stat(filename, &st) < 0){
|
if (stat(filename, &st) < 0){
|
||||||
clicon_err(OE_YANG, errno, "%s not found", filename);
|
clicon_err(OE_YANG, errno, "%s not found", filename);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if ((f = fopen(filename, "r")) == NULL){
|
if ((fd = open(filename, O_RDONLY)) < 0){
|
||||||
clicon_err(OE_UNIX, errno, "fopen(%s)", filename);
|
clicon_err(OE_YANG, errno, "open(%s)", filename);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
if ((ymod = yang_parse_file(fd, filename, ysp)) < 0)
|
||||||
len = 1024; /* any number is fine */
|
|
||||||
if ((buf = malloc(len)) == NULL){
|
|
||||||
perror("pt_file malloc");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
memset(buf, 0, len);
|
|
||||||
|
|
||||||
i = 0; /* position in buf */
|
|
||||||
while (1){ /* read the whole file */
|
|
||||||
if ((c = fgetc(f)) == EOF)
|
|
||||||
break;
|
|
||||||
if (len==i){
|
|
||||||
if ((buf = realloc(buf, 2*len)) == NULL){
|
|
||||||
fprintf(stderr, "%s: realloc: %s\n", __FUNCTION__, strerror(errno));
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
memset(buf+len, 0, len);
|
|
||||||
len *= 2;
|
|
||||||
}
|
|
||||||
buf[i++] = (char)(c&0xff);
|
|
||||||
} /* read a line */
|
|
||||||
if ((ymod = yang_parse_str(h, buf, filename, ysp)) < 0)
|
|
||||||
goto done;
|
goto done;
|
||||||
done:
|
done:
|
||||||
if (f)
|
if (fd != -1)
|
||||||
fclose(f);
|
close(fd);
|
||||||
if (buf)
|
|
||||||
free(buf);
|
|
||||||
return ymod; /* top-level (sub)module */
|
return ymod; /* top-level (sub)module */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1613,8 +1749,7 @@ yang_parse_file(clicon_handle h,
|
||||||
* @retval -1 Error
|
* @retval -1 Error
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
yang_parse_find_match(clicon_handle h,
|
yang_parse_find_match(const char *yang_dir,
|
||||||
const char *yang_dir,
|
|
||||||
const char *module,
|
const char *module,
|
||||||
cbuf *fbuf)
|
cbuf *fbuf)
|
||||||
{
|
{
|
||||||
|
|
@ -1658,7 +1793,7 @@ yang_parse_find_match(clicon_handle h,
|
||||||
* @param[in] h CLICON handle
|
* @param[in] h CLICON handle
|
||||||
* @param[in] yang_dir Directory where all YANG module files reside
|
* @param[in] yang_dir Directory where all YANG module files reside
|
||||||
* @param[in] module Name of main YANG module. Or absolute file name.
|
* @param[in] module Name of main YANG module. Or absolute file name.
|
||||||
* @param[in] revision Optional module revision date
|
* @param[in] revision Module revision date or NULL
|
||||||
* @param[in] ysp Yang specification. Should have been created by caller using yspec_new
|
* @param[in] ysp Yang specification. Should have been created by caller using yspec_new
|
||||||
* @retval ymod Top-level yang (sub)module
|
* @retval ymod Top-level yang (sub)module
|
||||||
* @retval NULL Error encountered
|
* @retval NULL Error encountered
|
||||||
|
|
@ -1671,8 +1806,7 @@ yang_parse_find_match(clicon_handle h,
|
||||||
* clixon_yang_parseparse # Actual yang parsing using yacc
|
* clixon_yang_parseparse # Actual yang parsing using yacc
|
||||||
*/
|
*/
|
||||||
static yang_stmt *
|
static yang_stmt *
|
||||||
yang_parse_recurse(clicon_handle h,
|
yang_parse_recurse(const char *yang_dir,
|
||||||
const char *yang_dir,
|
|
||||||
const char *module,
|
const char *module,
|
||||||
const char *revision,
|
const char *revision,
|
||||||
yang_spec *ysp)
|
yang_spec *ysp)
|
||||||
|
|
@ -1686,26 +1820,26 @@ yang_parse_recurse(clicon_handle h,
|
||||||
int nr;
|
int nr;
|
||||||
|
|
||||||
if (module[0] == '/'){
|
if (module[0] == '/'){
|
||||||
if ((ymod = yang_parse_file(h, module, ysp)) == NULL)
|
if ((ymod = yang_parse_filename(module, ysp)) == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if ((fbuf = cbuf_new()) == NULL){
|
if ((fbuf = cbuf_new()) == NULL){
|
||||||
clicon_err(OE_YANG, errno, "%s: cbuf_new", __FUNCTION__);
|
clicon_err(OE_YANG, errno, "cbuf_new");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (revision)
|
if (revision)
|
||||||
cprintf(fbuf, "%s/%s@%s.yang", yang_dir, module, revision);
|
cprintf(fbuf, "%s/%s@%s.yang", yang_dir, module, revision);
|
||||||
else{
|
else{
|
||||||
/* No specific revision, Match a yang file */
|
/* No specific revision, Match a yang file */
|
||||||
if ((nr = yang_parse_find_match(h, yang_dir, module, fbuf)) < 0)
|
if ((nr = yang_parse_find_match(yang_dir, module, fbuf)) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (nr == 0){
|
if (nr == 0){
|
||||||
clicon_err(OE_YANG, errno, "No matching %s yang files found (expected module name or absolute filename)", module);
|
clicon_err(OE_YANG, errno, "No matching %s yang files found in %s (expected module name or absolute filename)", module, yang_dir);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((ymod = yang_parse_file(h, cbuf_get(fbuf), ysp)) == NULL)
|
if ((ymod = yang_parse_filename(cbuf_get(fbuf), ysp)) == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1720,7 +1854,7 @@ yang_parse_recurse(clicon_handle h,
|
||||||
subrevision = NULL;
|
subrevision = NULL;
|
||||||
if (yang_find((yang_node*)ysp, Y_MODULE, modname) == NULL)
|
if (yang_find((yang_node*)ysp, Y_MODULE, modname) == NULL)
|
||||||
/* recursive call */
|
/* recursive call */
|
||||||
if (yang_parse_recurse(h, yang_dir, modname, subrevision, ysp) == NULL){
|
if (yang_parse_recurse(yang_dir, modname, subrevision, ysp) == NULL){
|
||||||
ymod = NULL;
|
ymod = NULL;
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
@ -1779,7 +1913,7 @@ ys_schemanode_check(yang_stmt *ys,
|
||||||
* @param[in] h CLICON handle
|
* @param[in] h CLICON handle
|
||||||
* @param[in] yang_dir Directory where all YANG module files reside (except mainfile)
|
* @param[in] yang_dir Directory where all YANG module files reside (except mainfile)
|
||||||
* @param[in] mainmod Name of main YANG module. Or absolute file name.
|
* @param[in] mainmod Name of main YANG module. Or absolute file name.
|
||||||
* @param[in] revision Optional main module revision date.
|
* @param[in] revision Main module revision date string or NULL
|
||||||
* @param[out] ysp Yang specification. Should ave been created by caller using yspec_new
|
* @param[out] ysp Yang specification. Should ave been created by caller using yspec_new
|
||||||
* @retval 0 Everything OK
|
* @retval 0 Everything OK
|
||||||
* @retval -1 Error encountered
|
* @retval -1 Error encountered
|
||||||
|
|
@ -1788,7 +1922,8 @@ ys_schemanode_check(yang_stmt *ys,
|
||||||
* @note if mainmod is filename, revision is not considered.
|
* @note if mainmod is filename, revision is not considered.
|
||||||
* Calling order:
|
* Calling order:
|
||||||
* yang_parse # Parse top-level yang module. Expand and populate yang tree
|
* yang_parse # Parse top-level yang module. Expand and populate yang tree
|
||||||
* yang_parse_recurse # Parse one yang module, go through its (sub)modules, parse them and then recursively parse them
|
* yang_parse_recurse # Parse one yang module, go through its (sub)modules,
|
||||||
|
* parse them and then recursively parse them
|
||||||
* yang_parse_file # Read yang file into a string
|
* yang_parse_file # Read yang file into a string
|
||||||
* yang_parse_str # Set up yacc parser and call it given a string
|
* yang_parse_str # Set up yacc parser and call it given a string
|
||||||
* clixon_yang_parseparse # Actual yang parsing using yacc
|
* clixon_yang_parseparse # Actual yang parsing using yacc
|
||||||
|
|
@ -1804,7 +1939,7 @@ yang_parse(clicon_handle h,
|
||||||
yang_stmt *ymod; /* Top-level yang (sub)module */
|
yang_stmt *ymod; /* Top-level yang (sub)module */
|
||||||
|
|
||||||
/* Step 1: parse from text to yang parse-tree. */
|
/* Step 1: parse from text to yang parse-tree. */
|
||||||
if ((ymod = yang_parse_recurse(h, yang_dir, mainmodule, revision, ysp)) == NULL)
|
if ((ymod = yang_parse_recurse(yang_dir, mainmodule, revision, ysp)) == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
/* Add top module name as dbspec-name */
|
/* Add top module name as dbspec-name */
|
||||||
clicon_dbspec_name_set(h, ymod->ys_argument);
|
clicon_dbspec_name_set(h, ymod->ys_argument);
|
||||||
|
|
@ -1988,16 +2123,16 @@ schema_nodeid_vec(yang_node *yn,
|
||||||
* Assume schema nodeid:s have prefixes, (actually the first).
|
* Assume schema nodeid:s have prefixes, (actually the first).
|
||||||
* @see yang_desc_schema_nodeid
|
* @see yang_desc_schema_nodeid
|
||||||
* @see RFC7950 6.5
|
* @see RFC7950 6.5
|
||||||
o schema node: A node in the schema tree. One of action, container,
|
* o schema node: A node in the schema tree. One of action, container,
|
||||||
leaf, leaf-list, list, choice, case, rpc, input, output,
|
* leaf, leaf-list, list, choice, case, rpc, input, output,
|
||||||
notification, anydata, and anyxml.
|
* notification, anydata, and anyxml.
|
||||||
* Used in yang: deviation, top-level augment
|
* Used in yang: deviation, top-level augment
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
yang_abs_schema_nodeid(yang_spec *yspec,
|
yang_abs_schema_nodeid(yang_spec *yspec,
|
||||||
char *schema_nodeid,
|
char *schema_nodeid,
|
||||||
enum rfc_6020 keyword,
|
enum rfc_6020 keyword,
|
||||||
yang_stmt **yres)
|
yang_stmt **yres)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
char **vec = NULL;
|
char **vec = NULL;
|
||||||
|
|
@ -2014,13 +2149,13 @@ yang_abs_schema_nodeid(yang_spec *yspec,
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if ((vec = clicon_strsep(schema_nodeid, "/", &nvec)) == NULL){
|
if ((vec = clicon_strsep(schema_nodeid, "/", &nvec)) == NULL){
|
||||||
clicon_err(OE_YANG, errno, "%s: strsep", __FUNCTION__);
|
clicon_err(OE_YANG, errno, "strsep");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
/* Assume schema nodeid looks like: "/prefix:id[/prefix:id]*" */
|
/* Assume schema nodeid looks like: "/prefix:id[/prefix:id]*" */
|
||||||
if (nvec < 2){
|
if (nvec < 2){
|
||||||
clicon_err(OE_YANG, 0, "%s: NULL or truncated path: %s",
|
clicon_err(OE_YANG, 0, "NULL or truncated path: %s",
|
||||||
__FUNCTION__, schema_nodeid);
|
schema_nodeid);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
/* split <prefix>:<id> */
|
/* split <prefix>:<id> */
|
||||||
|
|
@ -2029,7 +2164,7 @@ yang_abs_schema_nodeid(yang_spec *yspec,
|
||||||
goto ok;
|
goto ok;
|
||||||
}
|
}
|
||||||
if ((prefix = strdup(vec[1])) == NULL){
|
if ((prefix = strdup(vec[1])) == NULL){
|
||||||
clicon_err(OE_UNIX, errno, "%s: strdup", __FUNCTION__);
|
clicon_err(OE_UNIX, errno, "strdup");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
prefix[id-vec[1]] = '\0';
|
prefix[id-vec[1]] = '\0';
|
||||||
|
|
@ -2042,7 +2177,6 @@ yang_abs_schema_nodeid(yang_spec *yspec,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (ymod == NULL){ /* Try with topnode */
|
if (ymod == NULL){ /* Try with topnode */
|
||||||
|
|
||||||
if ((ys = yang_find_topnode(yspec, id, YC_SCHEMANODE)) == NULL){
|
if ((ys = yang_find_topnode(yspec, id, YC_SCHEMANODE)) == NULL){
|
||||||
clicon_err(OE_YANG, 0, "Module with id:%s:%s not found", prefix,id);
|
clicon_err(OE_YANG, 0, "Module with id:%s:%s not found", prefix,id);
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -2051,6 +2185,11 @@ yang_abs_schema_nodeid(yang_spec *yspec,
|
||||||
clicon_err(OE_YANG, 0, "Module with id:%s:%s not found2", prefix,id);
|
clicon_err(OE_YANG, 0, "Module with id:%s:%s not found2", prefix,id);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
if ((yprefix = yang_find((yang_node*)ymod, Y_PREFIX, NULL)) != NULL &&
|
||||||
|
strcmp(yprefix->ys_argument, prefix) != 0){
|
||||||
|
clicon_err(OE_YANG, 0, "Module with id:%s:%s not found", prefix,id);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (schema_nodeid_vec((yang_node*)ymod, vec+1, nvec-1, keyword, yres) < 0)
|
if (schema_nodeid_vec((yang_node*)ymod, vec+1, nvec-1, keyword, yres) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -2117,7 +2256,7 @@ ys_parse(yang_stmt *ys,
|
||||||
|
|
||||||
assert(ys->ys_cv == NULL); /* Cv:s are parsed in different places, difficult to separate */
|
assert(ys->ys_cv == NULL); /* Cv:s are parsed in different places, difficult to separate */
|
||||||
if ((ys->ys_cv = cv_new(cvtype)) == NULL){
|
if ((ys->ys_cv = cv_new(cvtype)) == NULL){
|
||||||
clicon_err(OE_YANG, errno, "%s: cv_new", __FUNCTION__);
|
clicon_err(OE_YANG, errno, "cv_new");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if ((cvret = cv_parse1(ys->ys_argument, ys->ys_cv, &reason)) < 0){ /* error */
|
if ((cvret = cv_parse1(ys->ys_argument, ys->ys_cv, &reason)) < 0){ /* error */
|
||||||
|
|
@ -2143,7 +2282,7 @@ ys_parse(yang_stmt *ys,
|
||||||
* That is, siblings, etc, may not be there. Complete checks are made in
|
* That is, siblings, etc, may not be there. Complete checks are made in
|
||||||
* ys_populate instead.
|
* ys_populate instead.
|
||||||
* @param[in] ys yang statement
|
* @param[in] ys yang statement
|
||||||
* @param[in] extra Yang extra for cornercases (unknown/extension)
|
* @param[in] extra Yang extra for cornercases (unknown/extension).
|
||||||
*
|
*
|
||||||
* The cv:s created in parse-tree as follows:
|
* The cv:s created in parse-tree as follows:
|
||||||
* fraction-digits : Create cv as uint8, check limits [1:8] (must be made in 1st pass)
|
* fraction-digits : Create cv as uint8, check limits [1:8] (must be made in 1st pass)
|
||||||
|
|
@ -2186,7 +2325,7 @@ ys_parse_sub(yang_stmt *ys,
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if ((ys->ys_cv = cv_new(CGV_STRING)) == NULL){
|
if ((ys->ys_cv = cv_new(CGV_STRING)) == NULL){
|
||||||
clicon_err(OE_YANG, errno, "%s: cv_new", __FUNCTION__);
|
clicon_err(OE_YANG, errno, "cv_new");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if ((cvret = cv_parse1(extra, ys->ys_cv, &reason)) < 0){ /* error */
|
if ((cvret = cv_parse1(extra, ys->ys_cv, &reason)) < 0){ /* error */
|
||||||
|
|
@ -2197,12 +2336,11 @@ ys_parse_sub(yang_stmt *ys,
|
||||||
clicon_err(OE_YANG, errno, "Parsing CV: %s", reason);
|
clicon_err(OE_YANG, errno, "Parsing CV: %s", reason);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
free(extra);
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
ok:
|
ok:
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
if (prefix)
|
if (prefix)
|
||||||
|
|
@ -2268,9 +2406,9 @@ yang_spec_netconf(clicon_handle h)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Read, parse and save application yang specification as option
|
/*! Read, parse and save application yang specification as option
|
||||||
* @param h clicon handle
|
* @param[in] h clicon handle
|
||||||
* @param f file to print to (if printspec enabled)
|
* @param[in] f file to print to (if printspec enabled)
|
||||||
* @param printspec print database (YANG) specification as read from file
|
* @param[in] printspec print database (YANG) specification as read from file
|
||||||
*/
|
*/
|
||||||
yang_spec*
|
yang_spec*
|
||||||
yang_spec_main(clicon_handle h)
|
yang_spec_main(clicon_handle h)
|
||||||
|
|
@ -2280,7 +2418,7 @@ yang_spec_main(clicon_handle h)
|
||||||
char *yang_module;
|
char *yang_module;
|
||||||
char *yang_revision;
|
char *yang_revision;
|
||||||
|
|
||||||
if ((yang_dir = clicon_yang_dir(h)) == NULL){
|
if ((yang_dir = clicon_yang_dir(h)) == NULL){
|
||||||
clicon_err(OE_FATAL, 0, "CLICON_YANG_DIR option not set");
|
clicon_err(OE_FATAL, 0, "CLICON_YANG_DIR option not set");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,6 @@ struct ys_stack{
|
||||||
};
|
};
|
||||||
|
|
||||||
struct clicon_yang_yacc_arg{ /* XXX: mostly unrelevant */
|
struct clicon_yang_yacc_arg{ /* XXX: mostly unrelevant */
|
||||||
clicon_handle yy_handle; /* cligen_handle */
|
|
||||||
char *yy_name; /* Name of syntax (for error string) */
|
char *yy_name; /* Name of syntax (for error string) */
|
||||||
int yy_linenum; /* Number of \n in parsed buffer */
|
int yy_linenum; /* Number of \n in parsed buffer */
|
||||||
char *yy_parse_string; /* original (copy of) parse string */
|
char *yy_parse_string; /* original (copy of) parse string */
|
||||||
|
|
|
||||||
|
|
@ -260,7 +260,7 @@ ysp_add(struct clicon_yang_yacc_arg *yy,
|
||||||
clicon_err(OE_YANG, errno, "No stack");
|
clicon_err(OE_YANG, errno, "No stack");
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
yn = ystack->ys_node;
|
assert(yn = ystack->ys_node);
|
||||||
if ((ys = ys_new(keyword)) == NULL)
|
if ((ys = ys_new(keyword)) == NULL)
|
||||||
goto err;
|
goto err;
|
||||||
/* NOTE: does not make a copy of string, ie argument is 'consumed' here */
|
/* NOTE: does not make a copy of string, ie argument is 'consumed' here */
|
||||||
|
|
@ -343,8 +343,9 @@ unknown_stmt : ustring ':' ustring ';'
|
||||||
}
|
}
|
||||||
| ustring ':' ustring ' ' string ';'
|
| ustring ':' ustring ' ' string ';'
|
||||||
{ char *id; if ((id=prefix_id_join($1, $3)) == NULL) _YYERROR("0");
|
{ char *id; if ((id=prefix_id_join($1, $3)) == NULL) _YYERROR("0");
|
||||||
if (ysp_add(_yy, Y_UNKNOWN, id, $5) == NULL) _YYERROR("0");
|
if (ysp_add(_yy, Y_UNKNOWN, id, $5) == NULL){ _YYERROR("0"); }
|
||||||
clicon_debug(2,"unknown-stmt -> ustring : ustring string");
|
clicon_debug(2,"unknown-stmt -> ustring : ustring string");
|
||||||
|
if ($5) free($5);
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,7 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <inttypes.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#define __USE_GNU /* strverscmp */
|
#define __USE_GNU /* strverscmp */
|
||||||
|
|
@ -354,7 +355,7 @@ clicon_type2cv(char *origtype,
|
||||||
if (restype != NULL){
|
if (restype != NULL){
|
||||||
yang2cv_type(restype, cvtype);
|
yang2cv_type(restype, cvtype);
|
||||||
if (*cvtype == CGV_ERR){
|
if (*cvtype == CGV_ERR){
|
||||||
clicon_err(OE_DB, 0, "%s: \"%s\" type not translated", __FUNCTION__, restype);
|
clicon_err(OE_DB, 0, "\"%s\" type not translated", restype);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -365,7 +366,7 @@ clicon_type2cv(char *origtype,
|
||||||
*/
|
*/
|
||||||
yang2cv_type(origtype, cvtype);
|
yang2cv_type(origtype, cvtype);
|
||||||
if (*cvtype == CGV_ERR){
|
if (*cvtype == CGV_ERR){
|
||||||
clicon_err(OE_DB, 0, "%s: \"%s\": type not resolved", __FUNCTION__, origtype);
|
clicon_err(OE_DB, 0, "\"%s\": type not resolved", origtype);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -380,7 +381,7 @@ clicon_type2cv(char *origtype,
|
||||||
(rmax && (i) > cv_##type##_get(rmax)))
|
(rmax && (i) > cv_##type##_get(rmax)))
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*! Validate CLIgen variable
|
||||||
* @retval -1 Error (fatal), with errno set to indicate error
|
* @retval -1 Error (fatal), with errno set to indicate error
|
||||||
* @retval 0 Validation not OK, malloced reason is returned. Free reason with free()
|
* @retval 0 Validation not OK, malloced reason is returned. Free reason with free()
|
||||||
* @retval 1 Validation OK
|
* @retval 1 Validation OK
|
||||||
|
|
@ -399,9 +400,13 @@ cv_validate1(cg_var *cv,
|
||||||
int retval = 1; /* OK */
|
int retval = 1; /* OK */
|
||||||
int retval2;
|
int retval2;
|
||||||
yang_stmt *yi = NULL;
|
yang_stmt *yi = NULL;
|
||||||
uint64_t u = 0;
|
unsigned int u = 0;
|
||||||
int64_t i = 0;
|
int i = 0;
|
||||||
char *str;
|
char *str;
|
||||||
|
int found;
|
||||||
|
char **vec = NULL;
|
||||||
|
int nvec;
|
||||||
|
char *v;
|
||||||
|
|
||||||
if (reason && *reason){
|
if (reason && *reason){
|
||||||
free(*reason);
|
free(*reason);
|
||||||
|
|
@ -413,7 +418,7 @@ cv_validate1(cg_var *cv,
|
||||||
i = cv_int8_get(cv);
|
i = cv_int8_get(cv);
|
||||||
if (range_check(i, range_min, range_max, int8)){
|
if (range_check(i, range_min, range_max, int8)){
|
||||||
if (reason)
|
if (reason)
|
||||||
*reason = cligen_reason("Number out of range: %ld", i);
|
*reason = cligen_reason("Number out of range: %d", i);
|
||||||
retval = 0;
|
retval = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -424,7 +429,7 @@ cv_validate1(cg_var *cv,
|
||||||
i = cv_int16_get(cv);
|
i = cv_int16_get(cv);
|
||||||
if (range_check(i, range_min, range_max, int16)){
|
if (range_check(i, range_min, range_max, int16)){
|
||||||
if (reason)
|
if (reason)
|
||||||
*reason = cligen_reason("Number out of range: %ld", i);
|
*reason = cligen_reason("Number out of range: %d", i);
|
||||||
retval = 0;
|
retval = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -435,29 +440,31 @@ cv_validate1(cg_var *cv,
|
||||||
i = cv_int32_get(cv);
|
i = cv_int32_get(cv);
|
||||||
if (range_check(i, range_min, range_max, int32)){
|
if (range_check(i, range_min, range_max, int32)){
|
||||||
if (reason)
|
if (reason)
|
||||||
*reason = cligen_reason("Number out of range: %ld", i);
|
*reason = cligen_reason("Number out of range: %d", i);
|
||||||
retval = 0;
|
retval = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case CGV_INT64:
|
case CGV_INT64:{
|
||||||
|
int64_t i64;
|
||||||
if ((options & YANG_OPTIONS_RANGE) != 0){
|
if ((options & YANG_OPTIONS_RANGE) != 0){
|
||||||
i = cv_int64_get(cv);
|
i64 = cv_int64_get(cv);
|
||||||
if (range_check(i, range_min, range_max, int64)){
|
if (range_check(i, range_min, range_max, int64)){
|
||||||
if (reason)
|
if (reason)
|
||||||
*reason = cligen_reason("Number out of range: %ld", i);
|
*reason = cligen_reason("Number out of range: %" PRId64, i64);
|
||||||
retval = 0;
|
retval = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case CGV_UINT8:
|
case CGV_UINT8:
|
||||||
if ((options & YANG_OPTIONS_RANGE) != 0){
|
if ((options & YANG_OPTIONS_RANGE) != 0){
|
||||||
u = cv_uint8_get(cv);
|
u = cv_uint8_get(cv);
|
||||||
if (range_check(u, range_min, range_max, uint8)){
|
if (range_check(u, range_min, range_max, uint8)){
|
||||||
if (reason)
|
if (reason)
|
||||||
*reason = cligen_reason("Number out of range: %lu", u);
|
*reason = cligen_reason("Number out of range: %u", u);
|
||||||
retval = 0;
|
retval = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -468,7 +475,7 @@ cv_validate1(cg_var *cv,
|
||||||
u = cv_uint16_get(cv);
|
u = cv_uint16_get(cv);
|
||||||
if (range_check(u, range_min, range_max, uint16)){
|
if (range_check(u, range_min, range_max, uint16)){
|
||||||
if (reason)
|
if (reason)
|
||||||
*reason = cligen_reason("Number out of range: %lu", u);
|
*reason = cligen_reason("Number out of range: %u", u);
|
||||||
retval = 0;
|
retval = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -479,29 +486,31 @@ cv_validate1(cg_var *cv,
|
||||||
u = cv_uint32_get(cv);
|
u = cv_uint32_get(cv);
|
||||||
if (range_check(u, range_min, range_max, uint32)){
|
if (range_check(u, range_min, range_max, uint32)){
|
||||||
if (reason)
|
if (reason)
|
||||||
*reason = cligen_reason("Number out of range: %lu", u);
|
*reason = cligen_reason("Number out of range: %u", u);
|
||||||
retval = 0;
|
retval = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case CGV_UINT64:
|
case CGV_UINT64:{
|
||||||
|
uint64_t u64;
|
||||||
if ((options & YANG_OPTIONS_RANGE) != 0){
|
if ((options & YANG_OPTIONS_RANGE) != 0){
|
||||||
u = cv_uint64_get(cv);
|
u64 = cv_uint64_get(cv);
|
||||||
if (range_check(u, range_min, range_max, uint64)){
|
if (range_check(u, range_min, range_max, uint64)){
|
||||||
if (reason)
|
if (reason)
|
||||||
*reason = cligen_reason("Number out of range: %lu", u);
|
*reason = cligen_reason("Number out of range: %" PRIu64, u64);
|
||||||
retval = 0;
|
retval = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case CGV_DEC64:
|
case CGV_DEC64:
|
||||||
if ((options & YANG_OPTIONS_RANGE) != 0){
|
if ((options & YANG_OPTIONS_RANGE) != 0){
|
||||||
i = cv_int64_get(cv);
|
i = cv_int64_get(cv);
|
||||||
if (range_check(i, range_min, range_max, int64)){
|
if (range_check(i, range_min, range_max, int64)){
|
||||||
if (reason)
|
if (reason)
|
||||||
*reason = cligen_reason("Number out of range: %ld", i);
|
*reason = cligen_reason("Number out of range: %d", i);
|
||||||
retval = 0;
|
retval = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -510,29 +519,57 @@ cv_validate1(cg_var *cv,
|
||||||
case CGV_STRING:
|
case CGV_STRING:
|
||||||
case CGV_REST:
|
case CGV_REST:
|
||||||
str = cv_string_get(cv);
|
str = cv_string_get(cv);
|
||||||
if (restype &&
|
if (restype){
|
||||||
(strcmp(restype, "enumeration") == 0 || strcmp(restype, "bits") == 0)){
|
if (strcmp(restype, "enumeration") == 0){
|
||||||
int found = 0;
|
found = 0;
|
||||||
while ((yi = yn_each((yang_node*)yrestype, yi)) != NULL){
|
while ((yi = yn_each((yang_node*)yrestype, yi)) != NULL){
|
||||||
if (yi->ys_keyword != Y_ENUM && yi->ys_keyword != Y_BIT)
|
if (yi->ys_keyword != Y_ENUM)
|
||||||
continue;
|
continue;
|
||||||
if (strcmp(yi->ys_argument, str) == 0){
|
if (strcmp(yi->ys_argument, str) == 0){
|
||||||
found++;
|
found++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!found){
|
||||||
|
if (reason)
|
||||||
|
*reason = cligen_reason("'%s' does not match enumeration", str);
|
||||||
|
retval = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!found){
|
if (strcmp(restype, "bits") == 0){
|
||||||
if (reason)
|
/* The lexical representation of the bits type is a space-separated list
|
||||||
*reason = cligen_reason("'%s' does not match enumeration", str);
|
* of the names of the bits that are set. A zero-length string thus
|
||||||
retval = 0;
|
* represents a value where no bits are set.
|
||||||
break;
|
*/
|
||||||
|
if ((vec = clicon_strsep(str, " \t", &nvec)) == NULL)
|
||||||
|
goto done;
|
||||||
|
for (i=0; i<nvec; i++){
|
||||||
|
if ((v = vec[i]) == NULL || !strlen(v))
|
||||||
|
continue;
|
||||||
|
found = 0;
|
||||||
|
while ((yi = yn_each((yang_node*)yrestype, yi)) != NULL){
|
||||||
|
if (yi->ys_keyword != Y_BIT)
|
||||||
|
continue;
|
||||||
|
if (strcmp(yi->ys_argument, v) == 0){
|
||||||
|
found++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!found){
|
||||||
|
if (reason)
|
||||||
|
*reason = cligen_reason("'%s' does not match enumeration", v);
|
||||||
|
retval = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((options & YANG_OPTIONS_LENGTH) != 0){
|
if ((options & YANG_OPTIONS_LENGTH) != 0){
|
||||||
u = strlen(str);
|
u = strlen(str);
|
||||||
if (range_check(u, range_min, range_max, uint64)){
|
if (range_check(u, range_min, range_max, uint64)){
|
||||||
if (reason)
|
if (reason)
|
||||||
*reason = cligen_reason("string length out of range: %lu", u);
|
*reason = cligen_reason("string length out of range: %u", u);
|
||||||
retval = 0;
|
retval = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -571,9 +608,11 @@ cv_validate1(cg_var *cv,
|
||||||
case CGV_EMPTY: /* XXX */
|
case CGV_EMPTY: /* XXX */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (reason && *reason)
|
if (reason && *reason)
|
||||||
assert(retval == 0); /* validation failed with error reason */
|
assert(retval == 0); /* validation failed with error reason */
|
||||||
|
done:
|
||||||
|
if (vec)
|
||||||
|
free(vec);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -713,8 +752,8 @@ ys_cv_validate(cg_var *cv,
|
||||||
if (cvtype == CGV_STRING && cv_type_get(ycv) == CGV_REST)
|
if (cvtype == CGV_STRING && cv_type_get(ycv) == CGV_REST)
|
||||||
;
|
;
|
||||||
else {
|
else {
|
||||||
clicon_err(OE_DB, 0, "%s: Type mismatch data:%s != yang:%s",
|
clicon_err(OE_DB, 0, "Type mismatch data:%s != yang:%s",
|
||||||
__FUNCTION__, cv_type2str(cvtype), cv_type2str(cv_type_get(ycv)));
|
cv_type2str(cvtype), cv_type2str(cv_type_get(ycv)));
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -728,7 +767,7 @@ ys_cv_validate(cg_var *cv,
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
if ((retval = cv_validate1(cv, cvtype, options, range_min, range_max, pattern,
|
if ((retval = cv_validate1(cv, cvtype, options, range_min, range_max, pattern,
|
||||||
yrestype, restype, reason)) < 0)
|
yrestype, restype, reason)) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
done:
|
done:
|
||||||
if (cvt)
|
if (cvt)
|
||||||
|
|
@ -764,9 +803,9 @@ ys_typedef_up(yang_stmt *ys)
|
||||||
return (yang_stmt*)ys;
|
return (yang_stmt*)ys;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Return yang-stmt of identity
|
/*! Find identity yang-stmt
|
||||||
This is a sanity check of base identity of identity-ref and for identity
|
This is a sanity check of base identity of identity-ref and for identity
|
||||||
statements.
|
statements when parsing.
|
||||||
|
|
||||||
Return true if node is identityref and is derived from identity_name
|
Return true if node is identityref and is derived from identity_name
|
||||||
The derived-from() function returns true if the (first) node (in
|
The derived-from() function returns true if the (first) node (in
|
||||||
|
|
@ -779,12 +818,17 @@ ys_typedef_up(yang_stmt *ys)
|
||||||
identityref's base identity.
|
identityref's base identity.
|
||||||
1. (base) identity must exist (be found). This is a sanity check
|
1. (base) identity must exist (be found). This is a sanity check
|
||||||
of the specification and also necessary for identity statements.
|
of the specification and also necessary for identity statements.
|
||||||
|
(This is what is dine here)
|
||||||
2. Check if a given node has value derived from base identity. This is
|
2. Check if a given node has value derived from base identity. This is
|
||||||
a run-time check necessary when validating eg netconf.
|
a run-time check necessary when validating eg netconf.
|
||||||
|
(This is validation)
|
||||||
3. Find all valid derived identities from a identityref base identity.
|
3. Find all valid derived identities from a identityref base identity.
|
||||||
This is for cli generation.
|
(This is for cli generation)
|
||||||
Så vad är det denna function ska göra? Svar: 1
|
* @param[in] ys Yang spec of id statement
|
||||||
*/
|
* @param[in] identity Identity string -check if it exists
|
||||||
|
* @retval 0 OK
|
||||||
|
* @see validate_identityref for (2) above
|
||||||
|
*/
|
||||||
yang_stmt *
|
yang_stmt *
|
||||||
yang_find_identity(yang_stmt *ys,
|
yang_find_identity(yang_stmt *ys,
|
||||||
char *identity)
|
char *identity)
|
||||||
|
|
@ -864,14 +908,14 @@ resolve_restrictions(yang_stmt *yrange,
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Recursively resolve a yang type to built-in type with optional restrictions
|
/*! Recursively resolve a yang type to built-in type with optional restrictions
|
||||||
* @param [in] ys yang-stmt from where the current search is based
|
* @param[in] ys yang-stmt from where the current search is based
|
||||||
* @param [in] ytype yang-stmt object containing currently resolving type
|
* @param[in] ytype yang-stmt object containing currently resolving type
|
||||||
* @param [out] yrestype resolved type. return built-in type or NULL. mandatory
|
* @param[out] yrestype resolved type. return built-in type or NULL. mandatory
|
||||||
* @param [out] options pointer to flags field of optional values. optional
|
* @param[out] options pointer to flags field of optional values. optional
|
||||||
* @param [out] mincv pointer to cv with min range or length. If options&YANG_OPTIONS_RANGE
|
* @param[out] mincv pointer to cv with min range or length. If options&YANG_OPTIONS_RANGE
|
||||||
* @param [out] maxcv pointer to cv with max range or length. If options&YANG_OPTIONS_RANGE
|
* @param[out] maxcv pointer to cv with max range or length. If options&YANG_OPTIONS_RANGE
|
||||||
* @param [out] pattern pointer to static string of yang string pattern. optional
|
* @param[out] pattern pointer to static string of yang string pattern. optional
|
||||||
* @param [out] fraction for decimal64, how many digits after period
|
* @param[out] fraction for decimal64, how many digits after period
|
||||||
* @retval 0 OK. Note yrestype may still be NULL.
|
* @retval 0 OK. Note yrestype may still be NULL.
|
||||||
* @retval -1 Error, clicon_err handles errors
|
* @retval -1 Error, clicon_err handles errors
|
||||||
* The setting of the options argument has the following semantics:
|
* The setting of the options argument has the following semantics:
|
||||||
|
|
@ -956,7 +1000,7 @@ yang_type_resolve(yang_stmt *ys,
|
||||||
if (rytypedef != NULL){ /* We have found a typedef */
|
if (rytypedef != NULL){ /* We have found a typedef */
|
||||||
/* Find associated type statement */
|
/* Find associated type statement */
|
||||||
if ((rytype = yang_find((yang_node*)rytypedef, Y_TYPE, NULL)) == NULL){
|
if ((rytype = yang_find((yang_node*)rytypedef, Y_TYPE, NULL)) == NULL){
|
||||||
clicon_err(OE_DB, 0, "%s: mandatory type object is not found", __FUNCTION__);
|
clicon_err(OE_DB, 0, "mandatory type object is not found");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
/* recursively resolve this new type */
|
/* recursively resolve this new type */
|
||||||
|
|
@ -994,14 +1038,14 @@ yang_type_resolve(yang_stmt *ys,
|
||||||
* if (options & YANG_OPTIONS_PATTERN != 0)
|
* if (options & YANG_OPTIONS_PATTERN != 0)
|
||||||
* printf("regexp: %s\n", pattern);
|
* printf("regexp: %s\n", pattern);
|
||||||
* @endcode
|
* @endcode
|
||||||
* @param [in] ys yang-stmt, leaf or leaf-list
|
* @param[in] ys yang-stmt, leaf or leaf-list
|
||||||
* @param [out] origtype original type may be derived or built-in
|
* @param[out] origtype original type may be derived or built-in
|
||||||
* @param [out] yrestype pointer to resolved type stmt. should be built-in or NULL
|
* @param[out] yrestype pointer to resolved type stmt. should be built-in or NULL
|
||||||
* @param [out] options pointer to flags field of optional values
|
* @param[out] options pointer to flags field of optional values
|
||||||
* @param [out] mincv pointer to cv of min range or length. optional
|
* @param[out] mincv pointer to cv of min range or length. optional
|
||||||
* @param [out] maxcv pointer to cv of max range or length. optional
|
* @param[out] maxcv pointer to cv of max range or length. optional
|
||||||
* @param [out] pattern pointer to static string of yang string pattern. optional
|
* @param[out] pattern pointer to static string of yang string pattern. optional
|
||||||
* @param [out] fraction for decimal64, how many digits after period
|
* @param[out] fraction for decimal64, how many digits after period
|
||||||
* @retval 0 OK, but note that restype==NULL means not resolved.
|
* @retval 0 OK, but note that restype==NULL means not resolved.
|
||||||
* @retval -1 Error, clicon_err handles errors
|
* @retval -1 Error, clicon_err handles errors
|
||||||
* The setting of the options argument has the following semantics:
|
* The setting of the options argument has the following semantics:
|
||||||
|
|
@ -1031,7 +1075,7 @@ yang_type_get(yang_stmt *ys,
|
||||||
*options = 0x0;
|
*options = 0x0;
|
||||||
/* Find mandatory type */
|
/* Find mandatory type */
|
||||||
if ((ytype = yang_find((yang_node*)ys, Y_TYPE, NULL)) == NULL){
|
if ((ytype = yang_find((yang_node*)ys, Y_TYPE, NULL)) == NULL){
|
||||||
clicon_err(OE_DB, 0, "%s: mandatory type object is not found", __FUNCTION__);
|
clicon_err(OE_DB, 0, "mandatory type object is not found");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
/* XXX: here we seem to have some problems if type is union */
|
/* XXX: here we seem to have some problems if type is union */
|
||||||
|
|
|
||||||
36
test/Jenkinsfile
vendored
Normal file
36
test/Jenkinsfile
vendored
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
node {
|
||||||
|
stage('Checkout') {
|
||||||
|
git url: 'https://github.com/clicon/clixon.git'
|
||||||
|
checkout scm
|
||||||
|
}
|
||||||
|
|
||||||
|
stage('Configure') {
|
||||||
|
/* `make check` returns non-zero on test failures,
|
||||||
|
* using `true` to allow the Pipeline to continue nonetheless
|
||||||
|
*/
|
||||||
|
sh 'make clean'
|
||||||
|
sh './configure'
|
||||||
|
}
|
||||||
|
|
||||||
|
stage('Make') {
|
||||||
|
/* `make check` returns non-zero on test failures,
|
||||||
|
* using `true` to allow the Pipeline to continue nonetheless
|
||||||
|
*/
|
||||||
|
sh 'make'
|
||||||
|
}
|
||||||
|
stage('Make install') {
|
||||||
|
sh 'sudo make install'
|
||||||
|
}
|
||||||
|
stage('Make install-include') {
|
||||||
|
sh 'sudo make install-include'
|
||||||
|
}
|
||||||
|
stage('Make Example') {
|
||||||
|
sh 'cd example'
|
||||||
|
sh 'make'
|
||||||
|
sh 'sudo make install'
|
||||||
|
}
|
||||||
|
stage('Testing') {
|
||||||
|
sh 'cd test'
|
||||||
|
sh './all.sh'
|
||||||
|
}
|
||||||
|
}
|
||||||
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