diff --git a/CHANGELOG.md b/CHANGELOG.md
index c2f19a40..4afe193a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,40 @@
# Clixon Changelog
+## 3.5.0 (Upcoming)
+
+### Major changes:
+* Major Restconf feature update to compy to RFC 8040. Thanks Stephen Jones for getting right.
+ * GET: Always return object referenced (and nothing else). ie, GET /restconf/data/X returns X.
+ * GET Added support for the following resources: Well-known, top-level resource, and yang library version,
+ * GET Single element JSON lists use {list:[element]}, not {list:element}.
+ * PUT Whole datastore
+
+### Minor changes:
+
+* Changed signature of plugin_credentials() restconf callback. Added a "user" parameter. To enable authentication and in preparation for access control a la RFC 6536.
+* Added RFC 6536 ietf-netconf-acm@2012-02-22.yang access control (but not implemented).
+* The following backward compatible options to configure have been _obsoleted_. If you havent already migrated this code you must do this now.
+ * `configure --with-startup-compat`. Configure option CLICON_USE_STARTUP_CONFIG is also obsoleted.
+ * `configure --with-config-compat`. The template clicon.conf.cpp files are also removed.
+ * `configure --with-xml-compat`
+
+* New configuration option: CLICON_RESTCONF_PRETTY. Default true. Set to false to get more compact Restconf output.
+
+
+* Default configure file handling generalized by Renato Botelho/Matt Smith. Config file FILE is selected in the following priority order:
+ * Provide -f FILE option when starting a program (eg clixon_backend -F FILE)
+ * Provide --with-configfile=FILE when configuring
+ * Provide --with-sysconfig=
when configuring, then FILE is /clixon.xml
+ * Provide --sysconfig= when configuring then FILE is /etc/clixon.xml
+ * FILE is /usr/local/etc/clixon.xml
+
+### Corrected Bugs
+* yang max keyword was not supported for string type. Corrected by setting "max" to MAXPATHLEN
+* Corrected "No yang spec" printed on tty when using leafref in CLI.
+* Fixed error in xml2cvec. If a (for example) int8 value has range error (eg 1000), it was treated as an error and the program terminated. Now this is just logged and skipped. Reported by Fredrik Pettai.
+
+### Known issues
+
## 3.4.0 (1 January 2018)
### Major changes:
diff --git a/Makefile.in b/Makefile.in
index b9cdb616..3041750f 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -56,7 +56,7 @@ SUBDIRS = lib apps include etc datastore yang
.PHONY: doc all clean depend $(SUBDIRS) install loc TAGS .config.status docker
-all: $(SUBDIRS) clixon.conf.cpp clixon.mk
+all: $(SUBDIRS) clixon.mk
$(SUBDIRS):
(cd $@ && $(MAKE) $(MFLAGS) all)
@@ -65,16 +65,11 @@ depend:
for i in $(SUBDIRS) doc example docker; \
do (cd $$i && $(MAKE) $(MFLAGS) depend); done
-# template clixon.conf file
-clixon.conf.cpp: clixon.conf.cpp.cpp
- $(CPP) -P -x assembler-with-cpp -Dprefix=$(prefix) -Dlocalstatedir=$(localstatedir) -Dsysconfdir=$(sysconfdir) -Ddatadir=$(datadir) -Dlibdir=$(libdir) $< > $@
-
clixon.mk: clixon.mk.cpp
$(CPP) -P -traditional-cpp -x assembler-with-cpp -Dprefix=$(prefix) -Dlocalstatedir=$(localstatedir) -Dsysconfdir=$(sysconfdir) -Ddatadir=$(datadir) -Dlibdir=$(libdir) $< > $@
-install: clixon.conf.cpp clixon.mk
+install: clixon.mk
install -d -m 755 $(DESTDIR)$(datadir)/clixon
- install -m 755 clixon.conf.cpp $(DESTDIR)$(datadir)/clixon
install -m 755 clixon.mk $(DESTDIR)$(datadir)/clixon
for i in $(SUBDIRS) doc; \
do (cd $$i; $(MAKE) $(MFLAGS) $@)||exit 1; done; \
@@ -88,7 +83,6 @@ install-include:
uninstall:
for i in $(SUBDIRS) doc example docker; \
do (cd $$i && $(MAKE) $(MFLAGS) $@)||exit 1; done;
- rm -f $(DESTDIR)$(datadir)/clixon/clixon.conf.cpp
rm -f $(DESTDIR)$(datadir)/clixon/clixon.mk
doc:
@@ -106,8 +100,7 @@ clean:
distclean:
rm -f Makefile TAGS config.status config.log *~ .depend
- rm -rf autom4te.cache
- rm -rf clixon.conf.cpp clixon.mk build-root/rpmbuild
+ rm -rf autom4te.cache clixon.mk build-root/rpmbuild
rm -f build-root/*.tar.xz build-root/*.rpm extras/rpm/Makefile
for i in $(SUBDIRS) doc example docker; \
do (cd $$i && $(MAKE) $(MFLAGS) $@); done
diff --git a/apps/backend/backend_client.c b/apps/backend/backend_client.c
index 0fd9fad6..97b0ae79 100644
--- a/apps/backend/backend_client.c
+++ b/apps/backend/backend_client.c
@@ -1095,8 +1095,8 @@ from_client(int s,
goto done;
retval = 0;
done:
+ clicon_debug(1, "%s retval=%d", __FUNCTION__, retval);
if (msg)
free(msg);
- clicon_debug(1, "%s retval=%d", __FUNCTION__, retval);
return retval; /* -1 here terminates backend */
}
diff --git a/apps/backend/backend_main.c b/apps/backend/backend_main.c
index 1b52b629..31cb39c2 100644
--- a/apps/backend/backend_main.c
+++ b/apps/backend/backend_main.c
@@ -73,11 +73,7 @@
#include "backend_handle.h"
/* Command line options to be passed to getopt(3) */
-#ifdef BACKEND_STARTUP_COMPAT
-#define BACKEND_OPTS "hD:f:d:b:Fzu:P:1s:c:IRCrg:y:x:" /* substitute s: for IRCc:r */
-#else
#define BACKEND_OPTS "hD:f:d:b:Fzu:P:1s:c:g:y:x:" /* substitute s: for IRCc:r */
-#endif
/*! Terminate. Cannot use h after this */
static int
@@ -142,12 +138,6 @@ usage(char *argv0, clicon_handle h)
" -P \tPid filename (default: %s)\n"
" -s \tSpecify backend startup mode: none|startup|running|init (replaces -IRCr\n"
" -c \tLoad extra xml configuration, but don't commit.\n"
-#ifdef BACKEND_STARTUP_COMPAT
- " -I\t\tInitialize running state database\n"
- " -R\t\tCall plugin_reset() in plugins to reset system state in running db (use with -I)\n"
- " -C\t\tCall plugin_reset() in plugins to reset system state in candidate db (use with -I)\n"
- " -r\t\tReload running database\n"
-#endif /* BACKEND_STARTUP_COMPAT */
" -g \tClient membership required to this group (default: %s)\n"
" -y \tOverride yang spec file (dont include .yang suffix)\n"
" -x \tXMLDB plugin\n",
@@ -270,161 +260,6 @@ plugin_start_useroptions(clicon_handle h,
return 0;
}
-#ifdef BACKEND_STARTUP_COMPAT
-/*! Initialize running-config from file application configuration
- *
- * @param[in] h clicon handle
- * @param[in] extraxml_file clicon application configuration file
- * @param[in] running_db Name of running db
- * @retval 0 OK
- * @retval -1 Error. clicon_err set
- */
-static int
-rundb_main(clicon_handle h,
- char *extraxml_file)
-{
- int retval = -1;
- int fd = -1;
- cxobj *xt = NULL;
- cxobj *xn;
-
- if (xmldb_create(h, "tmp") < 0)
- goto done;
- if (xmldb_copy(h, "running", "tmp") < 0)
- goto done;
- if ((fd = open(extraxml_file, O_RDONLY)) < 0){
- clicon_err(OE_UNIX, errno, "open(%s)", extraxml_file);
- goto done;
- }
- if (xml_parse_file(fd, &xt, "") < 0)
- goto done;
- if ((xn = xml_child_i(xt, 0)) != NULL)
- if (xmldb_put(h, "tmp", OP_MERGE, xn) < 0)
- goto done;
- if (candidate_commit(h, "tmp") < 0)
- goto done;
- if (xmldb_delete(h, "tmp") < 0)
- goto done;
- retval = 0;
-done:
- if (xt)
- xml_free(xt);
- if (fd != -1)
- close(fd);
- return retval;
-}
-
-static int
-candb_reset(clicon_handle h)
-{
- int retval = -1;
-
- if (xmldb_copy(h, "running", "tmp") < 0)
- goto done;
- /* Request plugins to reset system state, eg initiate running from system
- * -R
- */
- if (plugin_reset_state(h, "tmp") < 0)
- goto done;
- if (candidate_commit(h, "tmp") < 0)
- goto done;
- retval = 0;
- done:
- return retval;
-}
-
-/*! Legacy (old-style) startup mode where flags -IRCcr was used
- */
-static int
-fragmented_startup_mode(clicon_handle h,
- char *argv0,
- int argc,
- char *argv[],
- int reload_running,
- int init_rundb,
- int reset_state_candidate,
- int reset_state_running,
- char *extraxml_file)
-{
- int retval = -1;
-
- /* First check for startup config */
- if (clicon_option_int(h, "CLICON_USE_STARTUP_CONFIG") > 0){
- if (xmldb_exists(h, "startup") == 1){
- /* copy startup config -> running */
- if (xmldb_copy(h, "startup", "running") < 0)
- goto done;
- }
- else
- if (db_reset(h, "running") < 0)
- goto done;
- if (xmldb_create(h, "candidate") < 0)
- goto done;
- if (xmldb_copy(h, "running", "candidate") < 0)
- goto done;
- }
- /* If running exists and reload_running set, make a copy to candidate */
- if (reload_running){
- if (xmldb_exists(h, "running") != 1){
- clicon_log(LOG_NOTICE, "%s: -r (reload running) option given but no running_db found, proceeding without", __PROGRAM__);
- reload_running = 0; /* void it, so we dont commit candidate below */
- }
- else
- if (xmldb_copy(h, "running", "candidate") < 0)
- goto done;
- }
- /* Init running db
- * -I or if it isnt there
- */
- if (init_rundb || xmldb_exists(h, "running") != 1){
- if (db_reset(h, "running") < 0)
- goto done;
- }
- /* If candidate does not exist, create it from running */
- if (xmldb_exists(h, "candidate") != 1){
- if (xmldb_create(h, "candidate") < 0)
- goto done;
- if (xmldb_copy(h, "running", "candidate") < 0)
- goto done;
- }
-
- /* Load plugins and call plugin_init() */
- if (plugin_initiate(h) != 0)
- goto done;
-
- if (reset_state_candidate){
- if (candb_reset(h) < 0)
- goto done;
- }
- else
- if (reset_state_running){
- if (plugin_reset_state(h, "running") < 0)
- goto done;
- }
-
- if (plugin_start_useroptions(h, argv0, argc, argv) <0)
- goto done;
-
- if (reload_running){
- /* This could be a failed validation, and we should not fail for that */
- (void)candidate_commit(h, "candidate");
- }
-
- /* Have we specified a config file to load? eg
- * -c []
- */
- if (extraxml_file)
- if (rundb_main(h, extraxml_file) < 0)
- goto done;
- /* Initiate the shared candidate. */
- if (xmldb_copy(h, "running", "candidate") < 0)
- goto done;
- retval = 0;
- done:
- return retval;
-}
-#endif /* BACKEND_STARTUP_COMPAT */
-
/*! Merge xml in filename into database
*/
static int
@@ -648,12 +483,6 @@ main(int argc, char **argv)
int foreground;
int once;
enum startup_mode_t startup_mode;
-#ifdef BACKEND_STARTUP_COMPAT
- int init_rundb = 0;
- int reset_state_running = 0;
- int reset_state_candidate = 0;
- int reload_running = 0;
-#endif
char *extraxml_file;
char *config_group;
char *argv0 = argv[0];
@@ -769,20 +598,6 @@ main(int argc, char **argv)
case 'c': /* Load application config */
extraxml_file = optarg;
break;
-#ifdef BACKEND_STARTUP_COMPAT
- case 'I': /* Initiate running db */
- init_rundb++;
- break;
- case 'R': /* Reset state directly into running */
- reset_state_running++;
- break;
- case 'C': /* Reset state into candidate and then commit it */
- reset_state_candidate++;
- break;
- case 'r': /* Reload running */
- reload_running++;
- break;
-#endif /* BACKEND_STARTUP_COMPAT */
case 'g': /* config socket group */
clicon_option_str_set(h, "CLICON_SOCK_GROUP", optarg);
break;
@@ -890,19 +705,9 @@ main(int argc, char **argv)
goto done;
/* If startup mode is not defined, eg via OPTION or -s, assume old method */
startup_mode = clicon_startup_mode(h);
- if (startup_mode == -1){ /* Old style, fragmented mode, phase out */
-#ifdef BACKEND_STARTUP_COMPAT
- if (fragmented_startup_mode(h,
- argv0, argc, argv,
- reload_running, init_rundb,
- reset_state_candidate, reset_state_running,
- extraxml_file
- ) < 0)
- goto done;
-#else
+ if (startup_mode == -1){
clicon_log(LOG_ERR, "Startup mode undefined. Specify option CLICON_STARTUP_MODE or specify -s option to clicon_backend.\n");
goto done;
-#endif
}
else {
/* Init running db if it is not there
diff --git a/apps/cli/cli_generate.c b/apps/cli/cli_generate.c
index 3b8f2ce4..023b531d 100644
--- a/apps/cli/cli_generate.c
+++ b/apps/cli/cli_generate.c
@@ -238,12 +238,21 @@ yang2cli_var_sub(clicon_handle h,
goto done;
}
}
+
else{ /* Cligen does not have 'max' keyword in range so need to find actual
- max value of type if yang range expression is 0..max */
- if ((r = cvtype_max2str_dup(cvtype)) == NULL){
- clicon_err(OE_UNIX, errno, "cvtype_max2str");
- goto done;
+ max value of type if yang range expression is 0..max
+ */
+ if (cvtype==CGV_STRING){
+ if ((r = malloc(512)) == NULL){
+ clicon_err(OE_UNIX, errno, "malloc");
+ goto done;
+ }
+ snprintf(r, 512, "%d", MAXPATHLEN);
}
+ else if ((r = cvtype_max2str_dup(cvtype)) == NULL){
+ clicon_err(OE_UNIX, errno, "cvtype_max2str");
+ goto done;
+ }
}
cprintf(cb, "%s]", r);
free(r);
diff --git a/apps/cli/cli_show.c b/apps/cli/cli_show.c
index 10bfd062..0c3769d7 100644
--- a/apps/cli/cli_show.c
+++ b/apps/cli/cli_show.c
@@ -79,7 +79,7 @@
* Returns an expand-type list of commands as used by cligen 'expand'
* functionality.
*
- * Assume callback given in a cligen spec: a ")
* @param[in] h clicon handle
* @param[in] name Name of this function (eg "expand_dbvar")
* @param[in] cvv The command so far. Eg: cvec [0]:"a 5 b"; [1]: x=5;
@@ -88,7 +88,6 @@
* @param[out] commands vector of function pointers to callback functions
* @param[out] helptxt vector of pointers to helptexts
* @see cli_expand_var_generate This is where arg is generated
- * XXX: helptexts?
*/
int
expand_dbvar(void *h,
diff --git a/apps/restconf/README.md b/apps/restconf/README.md
index 807483d3..fdb1da37 100644
--- a/apps/restconf/README.md
+++ b/apps/restconf/README.md
@@ -2,14 +2,15 @@
### Features
Clixon restconf is a daemon based on FASTCGI. Instructions are available to
-run with NGINX.
-The implementatation supports plain OPTIONS, HEAD, GET, POST, PUT, PATCH, DELETE.
-and is based on draft-ietf-netconf-restconf-13.
-There is currently (2017) a [RFC 8040: RESTCONF Protocol](https://tools.ietf.org/html/rfc8040), many of those features are _not_ implemented,
-including:
+run with NGINX.
+The implementatation is based on [RFC 8040: RESTCONF Protocol](https://tools.ietf.org/html/rfc8040).
+The following featires are supported:
+- OPTIONS, HEAD, GET, POST, PUT, DELETE
+The following are not implemented
+- PATCH
- query parameters (section 4.9)
- notifications (sec 6)
-- only rudimentary error reporting exists (sec 7)
+- schema resource
### Installation using Nginx
diff --git a/apps/restconf/restconf_lib.c b/apps/restconf/restconf_lib.c
index 819ed211..15c868ca 100644
--- a/apps/restconf/restconf_lib.c
+++ b/apps/restconf/restconf_lib.c
@@ -148,7 +148,60 @@ restconf_code2reason(int code)
return clicon_int2str(http_reason_phrase_map, code);
}
-/*!
+/*! HTTP error 400
+ * @param[in] r Fastcgi request handle
+ */
+int
+badrequest(FCGX_Request *r)
+{
+ char *path;
+
+ clicon_debug(1, "%s", __FUNCTION__);
+ path = FCGX_GetParam("DOCUMENT_URI", r->envp);
+ FCGX_FPrintF(r->out, "Status: 400\r\n"); /* 400 bad request */
+ FCGX_FPrintF(r->out, "Content-Type: text/html\r\n\r\n");
+ FCGX_FPrintF(r->out, "