diff --git a/CHANGELOG b/CHANGELOG index 82e6473d..053ce8e9 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -30,6 +30,8 @@ # ***** END LICENSE BLOCK ***** +- Alternative yang spec option -y added to all applications +- Many clicon special string functions have been removed - The netconf support has been extended with lock/unlock - clicon_rpc_call() has been removed and should be replaced by extending the internal netconf protocol. diff --git a/apps/backend/backend_main.c b/apps/backend/backend_main.c index ce68fca5..6ee74fc9 100644 --- a/apps/backend/backend_main.c +++ b/apps/backend/backend_main.c @@ -57,6 +57,7 @@ #include #include #include +#include /* cligen */ #include @@ -141,7 +142,8 @@ usage(char *argv0, clicon_handle h) " -r\t\tReload running database\n" " -p \t\tPrint database yang specification\n" " -t \t\tPrint alternate spec translation (eg if YANG print KEY, if KEY print YANG)\n" - " -g \tClient membership required to this group (default: %s)\n", + " -g \tClient membership required to this group (default: %s)\n" + "\t-y \tOverride yang spec file (dont include .yang suffix)\n", argv0, plgdir ? plgdir : "none", confsock ? confsock : "none", @@ -426,9 +428,15 @@ main(int argc, char **argv) case 't' : /* Print alternative dbspec format (eg if YANG, print KEY) */ printalt++; break; - case 'y' : /* yang module */ - clicon_option_str_set(h, "CLICON_YANG_MODULE_MAIN", optarg); + case 'y' :{ /* yang module */ + /* Set revision to NULL, extract dir and module */ + char *str = strdup(optarg); + char *dir = dirname(str); + hash_del(clicon_options(h), (char*)"CLICON_YANG_MODULE_REVISION"); + clicon_option_str_set(h, "CLICON_YANG_MODULE_MAIN", basename(optarg)); + clicon_option_str_set(h, "CLICON_YANG_DIR", strdup(dir)); break; + } default: usage(argv[0], h); break; diff --git a/apps/cli/cli_common.c b/apps/cli/cli_common.c index 0ea1383c..9493ed8c 100644 --- a/apps/cli/cli_common.c +++ b/apps/cli/cli_common.c @@ -595,8 +595,7 @@ load_config_filev(clicon_handle h, { int ret = -1; struct stat st; - char **vecp = NULL; - char *filename; + char *filename = NULL; int replace; cg_var *cv; char *opstr; @@ -628,11 +627,10 @@ load_config_filev(clicon_handle h, clicon_err(OE_PLUGIN, 0, "No such var name: %s", varstr); goto done; } - if ((vecp = clicon_realpath(NULL, cv_string_get(cv), __FUNCTION__)) == NULL){ + if ((filename = realpath(cv_string_get(cv), NULL)) == NULL){ cli_output(stderr, "Failed to resolve filename\n"); goto done; } - filename = vecp[0]; if (stat(filename, &st) < 0){ clicon_err(OE_UNIX, 0, "load_config: stat(%s): %s", filename, strerror(errno)); @@ -668,14 +666,8 @@ load_config_filev(clicon_handle h, // } ret = 0; done: - unchunk_group(__FUNCTION__); - if (vecp){ - if (vecp[0]) - free(vecp[0]); - if (vecp[1]) - free(vecp[1]); - free(vecp); - } + if (filename) + free(filename); if (xt) xml_free(xt); if (fd != -1) @@ -704,8 +696,7 @@ save_config_filev(clicon_handle h, cvec *argv) { int retval = -1; - char **vecp; - char *filename; + char *filename = NULL; cg_var *cv; char *dbstr; char *varstr; @@ -732,11 +723,10 @@ save_config_filev(clicon_handle h, clicon_err(OE_PLUGIN, 0, "No such var name: %s", varstr); goto done; } - if ((vecp = clicon_realpath(NULL, cv_string_get(cv), __FUNCTION__)) == NULL){ + if ((filename = realpath(cv_string_get(cv), NULL)) == NULL){ cli_output(stderr, "Failed to resolve filename\n"); goto done; } - filename = vecp[0]; if (clicon_rpc_get_config(h, dbstr,"/", &xt) < 0) goto done; if ((f = fopen(filename, "wb")) == NULL){ @@ -748,7 +738,8 @@ save_config_filev(clicon_handle h, retval = 0; /* Fall through */ done: - unchunk_group(__FUNCTION__); + if (filename) + free(filename); if (xt) xml_free(xt); if (f != NULL) diff --git a/apps/cli/cli_main.c b/apps/cli/cli_main.c index 4a47ba78..23e179ce 100644 --- a/apps/cli/cli_main.c +++ b/apps/cli/cli_main.c @@ -54,6 +54,7 @@ #include #include #include +#include /* cligen */ #include @@ -69,7 +70,7 @@ #include "cli_handle.h" /* Command line options to be passed to getopt(3) */ -#define CLI_OPTS "hD:f:F:1u:d:m:qpGLl:" +#define CLI_OPTS "hD:f:F:1u:d:m:qpGLl:y:" /*! terminate cli application */ static int @@ -150,7 +151,8 @@ usage(char *argv0, clicon_handle h) "\t-p \t\tPrint database yang specification\n" "\t-G \t\tPrint CLI syntax generated from dbspec (if CLICON_CLI_GENMODEL enabled)\n" "\t-L \t\tDebug print dynamic CLI syntax including completions and expansions\n" - "\t-l \tLog on (s)yslog, std(e)rr or std(o)ut (stderr is default)\n", + "\t-l \tLog on (s)yslog, std(e)rr or std(o)ut (stderr is default)\n" + "\t-y \tOverride yang spec file (dont include .yang suffix)\n", argv0, confsock ? confsock : "none", plgdir ? plgdir : "none" @@ -288,6 +290,15 @@ main(int argc, char **argv) case 'L' : /* Debug print dynamic CLI syntax */ logclisyntax++; break; + case 'y' :{ /* yang module */ + /* Set revision to NULL, extract dir and module */ + char *str = strdup(optarg); + char *dir = dirname(str); + hash_del(clicon_options(h), (char*)"CLICON_YANG_MODULE_REVISION"); + clicon_option_str_set(h, "CLICON_YANG_MODULE_MAIN", basename(optarg)); + clicon_option_str_set(h, "CLICON_YANG_DIR", strdup(dir)); + break; + } default: usage(argv[0], h); break; diff --git a/apps/netconf/netconf_main.c b/apps/netconf/netconf_main.c index e585a273..de90a128 100644 --- a/apps/netconf/netconf_main.c +++ b/apps/netconf/netconf_main.c @@ -56,6 +56,7 @@ #include #include #include +#include /* cligen */ #include @@ -70,7 +71,7 @@ #include "netconf_rpc.h" /* Command line options to be passed to getopt(3) */ -#define NETCONF_OPTS "hDqf:d:S" +#define NETCONF_OPTS "hDqf:d:Sy:" /*! Process incoming packet * @param[in] h Clicon handle @@ -286,7 +287,8 @@ usage(clicon_handle h, "\t-q\t\tQuiet: dont send hello prompt\n" "\t-f \tConfiguration file (mandatory)\n" "\t-d \tSpecify netconf plugin directory dir (default: %s)\n" - "\t-S\t\tLog on syslog\n", + "\t-S\t\tLog on syslog\n" + "\t-y \tOverride yang spec file (dont include .yang suffix)\n", argv0, netconfdir ); @@ -359,6 +361,15 @@ main(int argc, char **argv) usage(h, argv[0]); clicon_option_str_set(h, "CLICON_NETCONF_DIR", optarg); break; + case 'y' :{ /* yang module */ + /* Set revision to NULL, extract dir and module */ + char *str = strdup(optarg); + char *dir = dirname(str); + hash_del(clicon_options(h), (char*)"CLICON_YANG_MODULE_REVISION"); + clicon_option_str_set(h, "CLICON_YANG_MODULE_MAIN", basename(optarg)); + clicon_option_str_set(h, "CLICON_YANG_DIR", strdup(dir)); + break; + } default: usage(h, argv[0]); break; diff --git a/apps/restconf/restconf_main.c b/apps/restconf/restconf_main.c index 41619c31..74642c82 100644 --- a/apps/restconf/restconf_main.c +++ b/apps/restconf/restconf_main.c @@ -59,6 +59,7 @@ #include #include #include +#include /* cligen */ #include @@ -71,7 +72,7 @@ #include "restconf_methods.h" /* Command line options to be passed to getopt(3) */ -#define RESTCONF_OPTS "hDf:p:" +#define RESTCONF_OPTS "hDf:p:y:" /* Should be discovered via "/.well-known/host-meta" resource ([RFC6415]) */ @@ -243,7 +244,8 @@ usage(clicon_handle h, "\t-h \t\tHelp\n" "\t-D \t\tDebug. Log to syslog\n" "\t-f \tConfiguration file (mandatory)\n" - "\t-d \tSpecify restconf plugin directory dir (default: %s)\n", + "\t-d \tSpecify restconf plugin directory dir (default: %s)\n" + "\t-y \tOverride yang spec file (dont include .yang suffix)\n", argv0, restconfdir ); @@ -264,6 +266,7 @@ main(int argc, char *sockpath; char *path; clicon_handle h; + char *yangspec=NULL; /* In the startup, logs to stderr & debug flag set later */ clicon_log_init(__PROGRAM__, LOG_INFO, CLICON_LOG_SYSLOG); @@ -289,6 +292,9 @@ main(int argc, usage(h, argv[0]); clicon_option_str_set(h, "CLICON_RESTCONF_DIR", optarg); break; + case 'y' : /* yang module */ + yangspec = optarg; + break; default: usage(h, argv[0]); break; @@ -312,6 +318,15 @@ main(int argc, if (clicon_options_main(h) < 0) goto done; + /* Overwrite yang module with -y option */ + if (yangspec){ + /* Set revision to NULL, extract dir and module */ + char *str = strdup(yangspec); + char *dir = dirname(str); + hash_del(clicon_options(h), (char*)"CLICON_YANG_MODULE_REVISION"); + clicon_option_str_set(h, "CLICON_YANG_MODULE_MAIN", basename(yangspec)); + clicon_option_str_set(h, "CLICON_YANG_DIR", strdup(dir)); + } /* Initialize plugins group */ if (restconf_plugin_load(h) < 0) return -1; diff --git a/lib/clixon/clixon_file.h b/lib/clixon/clixon_file.h index e3f807fc..7a57119b 100644 --- a/lib/clixon/clixon_file.h +++ b/lib/clixon/clixon_file.h @@ -37,8 +37,6 @@ #define _CLIXON_FILE_H_ -char **clicon_realpath(const char *cwd, char *path, const char *label); - int clicon_file_dirent(const char *dir, struct dirent **ent, const char *regexp, mode_t type, const char *label); diff --git a/lib/src/clixon_file.c b/lib/src/clixon_file.c index 1b96ed08..64ac8ee1 100644 --- a/lib/src/clixon_file.c +++ b/lib/src/clixon_file.c @@ -62,108 +62,6 @@ #include "clixon_string.h" #include "clixon_file.h" -/*! Resolve the real path of a given 'path', following symbolic links and '../'. - * If 'path' relative, it will be resolved based on the currnt working - * directory 'cwd'. The response is a 2 entry vector of strings. The first - * entry is the resolved path and the second is the part of the path which - * actually exist. - * @retval vec - */ -char ** -clicon_realpath(const char *cwd, - char *path, - const char *label) -{ - char **ret = NULL; - char *rest; - char **vec = NULL; - char **vec2; - int nvec, nvec2; - char *p; - char *rp = NULL; - char *ptr; - int i; - struct passwd *pwd; - char cwdbuf[PATH_MAX]; - - /* Prepend 'cwd' if not absolute */ - if (path[0] == '/') - p = path; - else { - if (cwd == NULL || strlen(cwd) == 0) - cwd = getcwd(cwdbuf, sizeof(cwdbuf)); - else if (cwd[0] == '~') { - if((pwd = getpwuid(getuid())) == NULL) - goto catch; - cwd = pwd->pw_dir; - } - p = chunk_sprintf(__FUNCTION__, "%s%s/%s", - (cwd[0]=='/' ? "" : "/"), cwd, path); - } - if (p == NULL) - goto catch; - - /* Make a local copy of 'path' */ - if ((path = chunkdup(p, strlen(p)+1, __FUNCTION__)) == NULL) - goto catch; - - /* Find the smallest portion of the path that exist and run realpath() */ - while(strlen(p) && ((rp = realpath(p, NULL)) == NULL)) { - if((ptr = strrchr(p, '/')) == NULL) - break; - *ptr = '\0'; - } - if(rp == NULL) - goto catch; - - /* Use the result of realpath() and the rest of 'path' untouched, to - form a new path */ - rest = path + strlen(p); - ptr = chunk_sprintf(__FUNCTION__, "%s%s", rp, rest); - p = ptr; - - /* Split path based on '/'. Loop through vector from the end and copy - each entry into a new vector, skipping '..' and it's previous directory - as well as all '.' */ - if ((vec = clicon_strsep(p, "/", &nvec)) == NULL) - goto catch; - if ((vec2 = malloc(nvec * sizeof(char *))) == NULL) - goto catch; - nvec2 = i = nvec; - while(--i >= 0) { - if(strcmp(vec[i], "..") == 0) - i--; /* Skip previous */ - else if(strcmp(vec[i], ".") == 0) - /* do nothing */ ; - else - vec2[--nvec2] = vec[i]; - } - - /* Create resulting vector */ - if ((ret = malloc(sizeof(char *) * 2)) != NULL) { - if((ret[0] = clicon_strjoin(nvec-nvec2, &vec2[nvec2], "/")) == NULL) { - free(ret); - ret = NULL; - } - if ((ret[1] = strdup(rp)) == NULL) { - free(ret[0]); - free(ret); - ret = NULL; - } - } - -catch: - if(rp) - free(rp); - if(vec) - free(vec); - if(vec2) - free(vec2); - unchunk_group(__FUNCTION__); - return ret; -} - - /* * qsort function */ @@ -354,24 +252,3 @@ clicon_file_copy(char *src, } -#ifdef NOTUSED -/* - * (un)lock a whole file. - * Arguments: - * fd - File descriptor - * cmd - F_GETLK, F_SETLK, F_SETLKW - * type - F_RDLCK, F_WRLCK, F_UNLCK - */ -int -file_lock(int fd, int cmd, int type) -{ - struct flock lock; - - lock.l_type = type; - lock.l_whence = SEEK_SET; - lock.l_start = 0; - lock.l_len = 0; - - return fcntl(fd, cmd, &lock); -} -#endif diff --git a/lib/src/clixon_string.c b/lib/src/clixon_string.c index ecf1431b..66c9c6b4 100644 --- a/lib/src/clixon_string.c +++ b/lib/src/clixon_string.c @@ -65,7 +65,7 @@ * @param[in] string String to be split * @param[in] delim String of delimiter characters * @param[out] nvec Number of entries in returned vector - * @retval vec Vector of strings. Free after use + * @retval vec Vector of strings. NULL terminated. Free after use * @retval NULL Error * */ char ** @@ -78,6 +78,7 @@ clicon_strsep(char *string, char *p; int nvec = 1; int i; + size_t siz; char *s; char *d; @@ -89,11 +90,13 @@ clicon_strsep(char *string, s++; } /* alloc vector and append copy of string */ - if ((vec = (char**)malloc(nvec* sizeof(char*) + strlen(string)+1)) == NULL){ + siz = (nvec+1)* sizeof(char*) + strlen(string)+1; + if ((vec = (char**)malloc(siz)) == NULL){ clicon_err(OE_UNIX, errno, "malloc"); goto done; } - ptr = (char*)vec + nvec* sizeof(char*); /* this is where ptr starts */ + memset(vec, 0, siz); + ptr = (char*)vec + (nvec+1)* sizeof(char*); /* this is where ptr starts */ strncpy(ptr, string, strlen(string)+1); i = 0; while ((p = strsep(&ptr, delim)) != NULL) @@ -190,10 +193,10 @@ main(int argc, char **argv) return 0; } str0 = argv[1]; - if ((vec = clicon_strsep("a b\tc", " \t", &nvec)) == NULL) + if ((vec = clicon_strsep(str0, " \t", &nvec)) == NULL) return -1; fprintf(stderr, "nvec: %d\n", nvec); - for (i=0; iys_argument, reason?reason:""); - if (reason) - free(reason); - goto done; + if ((body = xml_body(xt)) != NULL){ + if (cv_parse(body, cv) <0){ + clicon_err(OE_UNIX, errno, "cv_parse"); + goto done; + } + if ((ys_cv_validate(cv, ys, &reason)) != 1){ + clicon_err(OE_DB, 0, + "validation of %s failed %s", + ys->ys_argument, reason?reason:""); + if (reason) + free(reason); + goto done; + } } break; default: