From baa6e821a822ee5f6051e74e603dd303e54a0802 Mon Sep 17 00:00:00 2001 From: Olof hagsand Date: Wed, 10 Nov 2021 17:03:26 +0100 Subject: [PATCH] Fixed [yang in CLICON_YANG_MAIN_DIR can't import module's in CLICON_YANG_DIR recursively](https://github.com/clicon/clixon/issues/286) Which was a PR for [Recursive search CLIXON_YANG_DIR](https://github.com/clicon/clixon/issues/284) --- CHANGELOG.md | 1 + lib/clixon/clixon_file.h | 3 +- lib/src/clixon_file.c | 161 ++++++++++++++++---------------- lib/src/clixon_yang_parse_lib.c | 85 +++++++++++------ 4 files changed, 136 insertions(+), 114 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6688382b..c5a5bc69 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -68,6 +68,7 @@ Developers may need to change their code ### Minor features +* Added: [Recursive search CLIXON_YANG_DIR](https://github.com/clicon/clixon/issues/284) * Plugin context check before and after all callbacks. * Check blocked signals and signal handlers * Check termios settings diff --git a/lib/clixon/clixon_file.h b/lib/clixon/clixon_file.h index fcb7ce54..20526941 100644 --- a/lib/clixon/clixon_file.h +++ b/lib/clixon/clixon_file.h @@ -43,8 +43,7 @@ int clicon_file_dirent(const char *dir, struct dirent **ent, const char *regexp, mode_t type); -int clicon_files_recursive(const char *dir, const char *regexp, - char **dp, int *nent); +int clicon_files_recursive(const char *dir, const char *regexp, cvec *cvv); int clicon_file_copy(char *src, char *target); diff --git a/lib/src/clixon_file.c b/lib/src/clixon_file.c index 4adbe705..8553740b 100644 --- a/lib/src/clixon_file.c +++ b/lib/src/clixon_file.c @@ -62,86 +62,6 @@ #include "clixon_log.h" #include "clixon_file.h" -static int -clicon_file_string_sort(const void *arg1, - const void *arg2) -{ - char *str1 = *(char **)arg1; - char *str2 = *(char **)arg2; - - return strcmp(str1, str2); -} - -int -clicon_files_recursive(const char *dir, - const char *regexp, - char **dp, - int *nent) -{ - struct dirent *dent = NULL; - char path[MAXPATHLEN]; - DIR *dirp = NULL; - regex_t re; - int res; - char errbuf[128]; - - if (regexp && (res = regcomp(&re, regexp, REG_EXTENDED)) != 0) { - regerror(res, &re, errbuf, sizeof(errbuf)); - clicon_err(OE_DB, 0, "regcomp: %s", errbuf); - return -1; - } - - if (!(dirp = opendir(dir))) { - return *nent; - } - - while ((dent = readdir(dirp)) != NULL) { - if (dent->d_type == DT_DIR) { - /* If we find a directory we might want to enter it, unless it - is the current directory (.) or parent (..) */ - if (strcmp(dent->d_name, ".") == 0 || strcmp(dent->d_name, "..") == 0) { - continue; - } - - /* Build the new directory and enter it. */ - sprintf(path, "%s/%s", dir, dent->d_name); - *nent = clicon_files_recursive(path, regexp, dp, nent); - } else if (dent->d_type == DT_REG) { - /* If we encounter a file, match it against the regexp and - add it to the list of found files.*/ - if (regexp) { - if (regexec(&re, dent->d_name, (size_t)0, NULL, *nent) != 0) - continue; - } - - /* Add room for the new file. */ - if ((dp = (char **)realloc(dp, sizeof(char *) * (*nent + 1))) == NULL) { - clicon_err(OE_UNIX, errno, "realloc"); - *nent = -1; - goto quit; - } - - if ((dp[*nent] = (char *)malloc(1 + sizeof(char) * strlen(dir) + - strlen(dent->d_name))) == NULL) { - clicon_err(OE_UNIX, errno, "malloc"); - *nent = -1; - goto quit; - } - - sprintf(dp[*nent], "%s/%s", dir, dent->d_name); - (*nent)++; - } - } - - qsort(dp, *nent, sizeof(char *), clicon_file_string_sort); - - quit: - if (dirp) - closedir(dirp); - - return *nent; -} - /*! qsort "compar" for directory alphabetically sorting, see qsort(3) */ static int @@ -154,6 +74,85 @@ clicon_file_dirent_sort(const void* arg1, return strcoll(d1->d_name, d2->d_name); } +/*! + * @param[in,out] cvv On the format: (name, path)* + */ +static int +clicon_files_recursive1(const char *dir, + regex_t *re, + cvec *cvv) +{ + int retval = -1; + struct dirent *dent = NULL; + char path[MAXPATHLEN]; + DIR *dirp = NULL; + int res = 0; + struct stat st; + + if ((dirp = opendir(dir)) != NULL) + while ((dent = readdir(dirp)) != NULL) { + if (dent->d_type == DT_DIR) { + /* If we find a directory we might want to enter it, unless it + is the current directory (.) or parent (..) */ + if (strcmp(dent->d_name, ".") == 0 || strcmp(dent->d_name, "..") == 0) + continue; + + /* Build the new directory and enter it. */ + sprintf(path, "%s/%s", dir, dent->d_name); + if (clicon_files_recursive1(path, re, cvv) < 0) + goto done; + } + else if (dent->d_type == DT_REG) { + /* If we encounter a file, match it against the regexp and + add it to the list of found files.*/ + if (re != NULL && + regexec(re, dent->d_name, (size_t)0, NULL, 0) != 0) + continue; + snprintf(path, MAXPATHLEN-1, "%s/%s", dir, dent->d_name); + if ((res = lstat(path, &st)) != 0){ + clicon_err(OE_UNIX, errno, "lstat"); + goto done; + } + if ((st.st_mode & S_IFREG) == 0) + continue; + if (cvec_add_string(cvv, dent->d_name, path) < 0){ + clicon_err(OE_UNIX, errno, "cvec_add_string"); + goto done; + } + } + } + retval = 0; + done: + if (dirp) + closedir(dirp); + return retval; +} + +int +clicon_files_recursive(const char *dir, + const char *regexp, + cvec *cvv) +{ + int retval = -1; + regex_t re = {0,}; + int res = 0; + char errbuf[128]; + + clicon_debug(1, "%s dir:%s", __FUNCTION__, dir); + if (regexp && (res = regcomp(&re, regexp, REG_EXTENDED)) != 0) { + regerror(res, &re, errbuf, sizeof(errbuf)); + clicon_err(OE_DB, 0, "regcomp: %s", errbuf); + goto done; + } + if (clicon_files_recursive1(dir, &re, cvv) < 0) + goto done; + retval = 0; + done: + if (regexp) + regfree(&re); + return retval; +} + /*! Return alphabetically sorted files from a directory matching regexp * @param[in] dir Directory path * @param[out] ent Entries pointer, will be filled in with dir entries. Free @@ -177,7 +176,7 @@ clicon_file_dirent_sort(const void* arg1, int clicon_file_dirent(const char *dir, struct dirent **ent, - const char *regexp, + const char *regexp, mode_t type) { int retval = -1; diff --git a/lib/src/clixon_yang_parse_lib.c b/lib/src/clixon_yang_parse_lib.c index ceff764c..1f634bfd 100644 --- a/lib/src/clixon_yang_parse_lib.c +++ b/lib/src/clixon_yang_parse_lib.c @@ -903,14 +903,13 @@ yang_parse_find_match(clicon_handle h, cbuf *fbuf) { int retval = -1; - char **dp = NULL; - int ndp; cbuf *regex = NULL; cxobj *x; cxobj *xc; char *dir; - int nent = 0; - int i = 0; + cvec *cvv = NULL; + cg_var *cv = NULL; + cg_var *bestcv = NULL; /* get clicon config file in xml form */ if ((x = clicon_conf_xml(h)) == NULL) @@ -931,41 +930,65 @@ yang_parse_find_match(clicon_handle h, xc = NULL; while ((xc = xml_child_each(x, xc, CX_ELMNT)) != NULL) { - /* Skip if not yang dir */ - if (strcmp(xml_name(xc), "CLICON_YANG_DIR") != 0 && - strcmp(xml_name(xc), "CLICON_YANG_MAIN_DIR") != 0) - continue; - dir = xml_body(xc); + if (strcmp(xml_name(xc), "CLICON_YANG_MAIN_DIR") == 0){ + struct dirent *dp = NULL; + int ndp; - /* get all matching files in this directory */ - dp = (char **)malloc(sizeof(char *)); - if ((ndp = clicon_files_recursive(dir, - cbuf_get(regex), - dp, - &nent)) < 0) { - goto done; - } + dir = xml_body(xc); + /* get all matching files in this directory */ + if ((ndp = clicon_file_dirent(dir, + &dp, + cbuf_get(regex), + S_IFREG)) < 0) + goto done; + /* Entries are sorted, last entry should be most recent date + */ + if (ndp != 0){ + cprintf(fbuf, "%s/%s", dir, dp[ndp-1].d_name); + retval = 1; + goto done; + } + if (dp) + free(dp); + } + else if (strcmp(xml_name(xc), "CLICON_YANG_DIR") == 0){ + dir = xml_body(xc); + /* get all matching files in this directory recursively */ + if ((cvv = cvec_new(0)) == NULL){ + clicon_err(OE_UNIX, errno, "cvec_new"); + goto done; + } + if (clicon_files_recursive(dir, cbuf_get(regex), cvv) < 0) + goto done; - /* Entries are sorted, last entry should be most recent date - */ - if (ndp != 0){ - cprintf(fbuf, "%s", dp[ndp-1]); - - for (i = 0; i < nent; i++) - if (dp[i]) - free(dp[i]); - - retval = 1; - goto done; - } + /* Entries are not sorted and come in a vector: . + * Find latest name and use path as return value + */ + bestcv = NULL; + while ((cv = cvec_each(cvv, cv)) != NULL){ + if (bestcv == NULL) + bestcv = cv; + else if (strcoll(cv_name_get(cv), cv_name_get(bestcv)) > 0) + bestcv = cv; + } + if (bestcv){ + cprintf(fbuf, "%s", cv_string_get(bestcv)); /* file path */ + retval = 1; /* found */ + goto done; + } + if (cvv){ + cvec_free(cvv); + cvv = NULL; + } + } } ok: retval = 0; done: + if (cvv) + cvec_free(cvv); if (regex) cbuf_free(regex); - if (dp) - free(dp); return retval; }