From 3dd9b3710a6724538c9b87581a1d7182808f3ba3 Mon Sep 17 00:00:00 2001 From: Jonathan Aillet Date: Tue, 3 Dec 2019 19:10:58 +0100 Subject: Improve plugin search path In controller 'plugin' section, use only paths available with 'spath' key to search for plugins. Multiple paths can be specified using ':' character as separator. Environment variables can be used in paths. If a path is not absolute, it will be added two times to search paths list, one with binder root directory as prefix, and one with binding parent directory. BUG-AGL: SPEC-3011 Change-Id: I1e3fd64d523d36a0e0982bbd31d66ae8d9960d3c Signed-off-by: Jonathan Aillet --- ctl-lib/ctl-config.c | 10 +- ctl-lib/ctl-lua.c | 4 +- ctl-lib/ctl-plugin.c | 336 ++++++++++++++++++++++++++++++++++++++++++++------- ctl-lib/ctl-plugin.h | 3 +- 4 files changed, 303 insertions(+), 50 deletions(-) diff --git a/ctl-lib/ctl-config.c b/ctl-lib/ctl-config.c index 2970955..9039ac5 100644 --- a/ctl-lib/ctl-config.c +++ b/ctl-lib/ctl-config.c @@ -225,7 +225,7 @@ json_object* CtlUpdateSectionConfig(afb_api_t apiHandle, CtlConfigT *ctlHandle, json_object *sectionArrayJ; char *oneFile = NULL; - const char *bindingPath = GetBindingDirPath(apiHandle); + const char *bindingParentPath = GetBindingParentDirPath(apiHandle); if(! json_object_is_type(sectionJ, json_type_array)) { sectionArrayJ = json_object_new_array(); @@ -243,9 +243,9 @@ json_object* CtlUpdateSectionConfig(afb_api_t apiHandle, CtlConfigT *ctlHandle, for (int idx=0; idx < length; idx++) { json_object *oneFileJ = json_object_array_get_idx(filesJ, idx); json_object *responseJ = - ScanForConfig(bindingPath, CTL_SCAN_RECURSIVE, json_object_get_string(oneFileJ), ".json"); + ScanForConfig(bindingParentPath, CTL_SCAN_RECURSIVE, json_object_get_string(oneFileJ), ".json"); if(!responseJ) { - AFB_API_ERROR(apiHandle, "No config files found in search path. No changes has been made\n -- %s", bindingPath); + AFB_API_ERROR(apiHandle, "No config files found in search path. No changes has been made\n -- %s", bindingParentPath); return sectionArrayJ; } oneFile = ConfigSearch(apiHandle, responseJ); @@ -261,9 +261,9 @@ json_object* CtlUpdateSectionConfig(afb_api_t apiHandle, CtlConfigT *ctlHandle, } } else { json_object *responseJ = - ScanForConfig(bindingPath, CTL_SCAN_RECURSIVE, json_object_get_string(filesJ), ".json"); + ScanForConfig(bindingParentPath, CTL_SCAN_RECURSIVE, json_object_get_string(filesJ), ".json"); if(!responseJ) { - AFB_API_ERROR(apiHandle, "No config files found in search path. No changes has been made\n -- %s", bindingPath); + AFB_API_ERROR(apiHandle, "No config files found in search path. No changes has been made\n -- %s", bindingParentPath); return sectionArrayJ; } oneFile = ConfigSearch(apiHandle, responseJ); diff --git a/ctl-lib/ctl-lua.c b/ctl-lib/ctl-lua.c index 5509385..f3f0dce 100644 --- a/ctl-lib/ctl-lua.c +++ b/ctl-lib/ctl-lua.c @@ -713,7 +713,7 @@ static int LuaAfbGetRootDir(lua_State* luaState) { } // extract and return afbSource from timer handle - lua_pushstring(luaState, GetBindingDirPath(source->api)); + lua_pushstring(luaState, GetAFBRootDirPath(source->api)); return 1; // return argument } @@ -1377,7 +1377,7 @@ int LuaConfigLoad(afb_api_t apiHandle, const char *prefix) { // set package.path lua variable use the CONTROL_PLUGIN_PATH as it could // have to find external lua packages in those directories - spath = GetDefaultPluginSearchPath(apiHandle, prefix); + spath = GetDefaultPluginSearchPath(apiHandle); base_len = strlen(LUA_PATH_VALUE); spath_len = strlen(spath); diff --git a/ctl-lib/ctl-plugin.c b/ctl-lib/ctl-plugin.c index e60bd5e..6a446c9 100644 --- a/ctl-lib/ctl-plugin.c +++ b/ctl-lib/ctl-plugin.c @@ -249,51 +249,299 @@ static int LoadFoundPlugins(afb_api_t apiHandle, json_object *scanResult, json_o return 0; } -char *GetDefaultPluginSearchPath(afb_api_t apiHandle, const char *prefix) +char *GetBindingParentDirPath(afb_api_t apiHandle) { - char *searchPath, *rootDir, *path; - const char *bindingPath; - const char *envDirList; - size_t envDirList_len; - json_object *settings = afb_api_settings(apiHandle); - json_object *bpath; - - if(json_object_object_get_ex(settings, "binding-path", &bpath)) { - rootDir = strdup(json_object_get_string(bpath)); - path = rindex(rootDir, '/'); - if(strlen(path) < 3) - return NULL; - *++path = '.'; - *++path = '.'; - *++path = '\0'; - } - else { - rootDir = malloc(1); - strcpy(rootDir, ""); - } - - bindingPath = GetBindingDirPath(apiHandle); - envDirList = getEnvDirList(prefix, "PLUGIN_PATH"); - - /* Allocating with the size of binding root dir path + environment if found - * for the NULL terminating character and the additional separator - * between bindingPath and envDirList concatenation. - */ - if(envDirList) { - envDirList_len = strlen(envDirList) + strlen(bindingPath) + strlen(rootDir) + 3; - searchPath = malloc(envDirList_len + 1); - snprintf(searchPath, envDirList_len + 1, "%s:%s:%s", rootDir, bindingPath, envDirList); + int ret; + char *bindingDirPath, *bindingParentDirPath = NULL; + + if(! apiHandle) + return NULL; + + bindingDirPath = GetRunningBindingDirPath(apiHandle); + if(! bindingDirPath) + return NULL; + + ret = asprintf(&bindingParentDirPath, "%s/..", bindingDirPath); + free(bindingDirPath); + if(ret <= 3) + return NULL; + + return bindingParentDirPath; +} + +char *GetDefaultPluginSearchPath(afb_api_t apiHandle) +{ + size_t searchPathLength; + char *searchPath, *binderRootDirPath, *bindingParentDirPath; + + if(! apiHandle) + return NULL; + + binderRootDirPath = GetAFBRootDirPath(apiHandle); + if(! binderRootDirPath) + return NULL; + + bindingParentDirPath = GetBindingParentDirPath(apiHandle); + if(! bindingParentDirPath) { + free(binderRootDirPath); + return NULL; } - else { - envDirList_len = strlen(bindingPath) + strlen(rootDir) + 2; - searchPath = malloc(envDirList_len + 1); - snprintf(searchPath, envDirList_len + 1, "%s:%s", rootDir, bindingPath); + + /* Allocating with the size of binding root dir path + binding parent directory path + * + 1 character for the NULL terminating character + 1 character for the additional separator + * between binderRootDirPath and bindingParentDirPath. + */ + searchPathLength = strlen(binderRootDirPath) + strlen(bindingParentDirPath) + 2; + + searchPath = malloc(searchPathLength); + if(! searchPath) { + free(binderRootDirPath); + free(bindingParentDirPath); + return NULL; } - free(rootDir); + snprintf(searchPath, searchPathLength, "%s:%s", binderRootDirPath, bindingParentDirPath); + + free(binderRootDirPath); + free(bindingParentDirPath); + return searchPath; } +int isCharIsAllowedInEnvironmentVariable(char envChar) +{ + if(envChar < '0') + return 0; + + if((envChar >= '0' && envChar <= '9') || + (envChar >= 'A' && envChar <= 'Z') || + (envChar >= 'a' && envChar <= 'z') || + envChar == '_') + return 1; + + return 0; +} + +char *ExpandPath(const char *path) +{ + int cpt, + pathLength, + pathPartCount = 0, + currentPartNb = -1, + currentPartBegin, + currentlyInEnvVar, + newPartDetected = 1, + expandedPathLength = 0, + expandedPathIdx = 0; + int *pathPartLengths; + + char currentChar; + char *pathToExpand, *expandedpath; + char **pathPartStrings; + + if(! path) + return NULL; + + pathLength = (int) strlen(path); + if(! pathLength) + return NULL; + + pathToExpand = strdup(path); + if(! pathToExpand) + return NULL; + + for(cpt = 1; cpt <= pathLength; cpt++) { + if(newPartDetected) { + newPartDetected = 0; + currentlyInEnvVar = (pathToExpand[cpt - 1] == '$') ? 1 : 0; + pathPartCount++; + } + + if((currentlyInEnvVar && ! isCharIsAllowedInEnvironmentVariable(pathToExpand[cpt])) || + (! currentlyInEnvVar && pathToExpand[cpt] == '$')) + newPartDetected = 1; + } + + if(pathPartCount == 1) { + if(currentlyInEnvVar) { + expandedpath = getenv(&pathToExpand[1]); + free(pathToExpand); + if(! expandedpath) + return NULL; + return strdup(expandedpath); + } + else { + return pathToExpand; + } + } + + pathPartLengths = (int *) alloca(pathPartCount * (sizeof(int))); + if(! pathPartLengths) { + free(pathToExpand); + return NULL; + } + + pathPartStrings = (char **) alloca(pathPartCount * (sizeof(char *))); + if(! pathPartStrings) { + free(pathToExpand); + return NULL; + } + + newPartDetected = 1; + currentChar = pathToExpand[0]; + + for(cpt = 1; cpt <= pathLength; cpt++) { + if(newPartDetected) { + newPartDetected = 0; + currentlyInEnvVar = (currentChar == '$') ? 1 : 0; + currentPartNb++; + currentPartBegin = cpt - 1; + } + + currentChar = pathToExpand[cpt]; + + if(currentlyInEnvVar && ! isCharIsAllowedInEnvironmentVariable(currentChar)) { + newPartDetected = 1; + + pathToExpand[cpt] = '\0'; + + pathPartStrings[currentPartNb] = getenv(&pathToExpand[currentPartBegin + 1]); + if(! pathPartStrings[currentPartNb]) { + free(pathToExpand); + return NULL; + } + + pathToExpand[cpt] = currentChar; + + pathPartLengths[currentPartNb] = (int) strlen(pathPartStrings[currentPartNb]); + } + + if(! currentlyInEnvVar && + (! currentChar || currentChar == '$')) { + newPartDetected = 1; + + pathToExpand[cpt] = '\0'; + + pathPartStrings[currentPartNb] = &pathToExpand[currentPartBegin]; + pathPartLengths[currentPartNb] = cpt - currentPartBegin; + } + + if(newPartDetected) + expandedPathLength += pathPartLengths[currentPartNb]; + } + + expandedPathLength++; + + expandedpath = malloc(expandedPathLength * sizeof(char)); + if(! expandedpath) { + free(pathToExpand); + return NULL; + } + + for(cpt = 0; cpt < pathPartCount; cpt++) { + strcpy(&expandedpath[expandedPathIdx], pathPartStrings[cpt]); + expandedPathIdx += pathPartLengths[cpt]; + } + + free(pathToExpand); + + return expandedpath; +} + +char *ExpandPluginSearchPath(afb_api_t apiHandle, const char *sPath) +{ + char *binderRootDirPath = NULL, + *bindingParentDirPath = NULL, + *sPathToExpand = NULL, + *currentPathToExpand, + *expandedPath = NULL, + *expandedAbsolutePath, + *expandedSearchPath = NULL, + *newExpandedSearchPath; + + if(! apiHandle || ! sPath) { + AFB_API_ERROR(apiHandle, "Invalid argument(s)"); + goto OnErrorExit; + } + + binderRootDirPath = GetAFBRootDirPath(apiHandle); + if(! binderRootDirPath) { + AFB_API_ERROR(apiHandle, "An error happened when tried to get binder root directory path"); + goto OnErrorExit; + } + + bindingParentDirPath = GetBindingParentDirPath(apiHandle); + if(! bindingParentDirPath) { + AFB_API_ERROR(apiHandle, "An error happened when tried to get binding parent directory path"); + goto OnErrorExit; + } + + sPathToExpand = strdup(sPath); + if(! sPathToExpand) { + AFB_API_ERROR(apiHandle, "Error while allocating copy of paths to expand"); + goto OnErrorExit; + } + + for(currentPathToExpand = strtok(sPathToExpand, ":"); + currentPathToExpand && *currentPathToExpand; + currentPathToExpand = strtok(NULL, ":")) { + expandedPath = ExpandPath(currentPathToExpand); + if(! expandedPath) { + AFB_API_NOTICE(apiHandle, + "An error happened when tried to expand plugin path '%s' string, will be ignored when searching for plugins", + currentPathToExpand); + continue; + } + + expandedAbsolutePath = NULL; + if(expandedPath[0] == '/') { + expandedAbsolutePath = strdup(expandedPath); + } + else if(asprintf(&expandedAbsolutePath, "%s/%s:%s/%s", binderRootDirPath, expandedPath, bindingParentDirPath, expandedPath) < 7) { + AFB_API_ERROR(apiHandle, "Error while allocating whole absolute expanded path"); + goto OnErrorExit; + } + + if(! expandedAbsolutePath) { + AFB_API_ERROR(apiHandle, "Error while allocating absolute expanded path"); + goto OnErrorExit; + } + + free(expandedPath); + expandedPath = NULL; + + newExpandedSearchPath = NULL; + if(! expandedSearchPath) { + newExpandedSearchPath = strdup(expandedAbsolutePath); + } + else if((asprintf(&newExpandedSearchPath, "%s:%s", expandedSearchPath, expandedAbsolutePath) < 3) || + ! newExpandedSearchPath) { + AFB_API_ERROR(apiHandle, "Error while allocating new search paths string"); + free(expandedAbsolutePath); + goto OnErrorExit; + } + + free(expandedAbsolutePath); + free(expandedSearchPath); + + expandedSearchPath = newExpandedSearchPath; + } + + free(binderRootDirPath); + free(bindingParentDirPath); + free(sPathToExpand); + + return expandedSearchPath; + +OnErrorExit: + free(binderRootDirPath); + free(bindingParentDirPath); + free(sPathToExpand); + free(expandedPath); + free(expandedSearchPath); + return NULL; +} + static int FindPlugins(afb_api_t apiHandle, const char *searchPath, const char *file, json_object **pluginPathJ) { *pluginPathJ = ScanForConfig(searchPath, CTL_SCAN_RECURSIVE, file, NULL); @@ -308,7 +556,7 @@ static int FindPlugins(afb_api_t apiHandle, const char *searchPath, const char * static int PluginLoad (afb_api_t apiHandle, CtlPluginT *ctlPlugin, json_object *pluginJ, void *handle, const char *prefix) { int err = 0, i = 0; - char *searchPath; + char *searchPath = NULL; const char *sPath = NULL, *file = NULL, *lua2c_prefix = NULL; json_object *luaJ = NULL, *lua2csJ = NULL, *fileJ = NULL, *pluginPathJ = NULL; @@ -339,9 +587,13 @@ static int PluginLoad (afb_api_t apiHandle, CtlPluginT *ctlPlugin, json_object * } // if search path not in Json config file, then try default - searchPath = (sPath) ? - strdup(sPath) : - GetDefaultPluginSearchPath(apiHandle, prefix); + if(sPath) + searchPath = ExpandPluginSearchPath(apiHandle, sPath); + + if(!searchPath) + searchPath = GetDefaultPluginSearchPath(apiHandle); + + AFB_API_DEBUG(apiHandle, "Plugin search path : '%s'", searchPath); // default file equal uid if (!fileJ) { diff --git a/ctl-lib/ctl-plugin.h b/ctl-lib/ctl-plugin.h index 47076f7..f500307 100644 --- a/ctl-lib/ctl-plugin.h +++ b/ctl-lib/ctl-plugin.h @@ -135,7 +135,8 @@ typedef int (*Lua2cWrapperT) (void*luaHandle, const char *funcname, Lua2cFunctio int lua2c_ ## funcname (void* luaState){return((*Lua2cWrap)(luaState, MACRO_STR_VALUE(funcname), funcname));};\ int funcname (CtlSourceT* source, json_object* argsJ, json_object** responseJ) -extern char *GetDefaultPluginSearchPath(afb_api_t apiHandle, const char *prefix); +extern char *GetBindingParentDirPath(afb_api_t apiHandle); +extern char *GetDefaultPluginSearchPath(afb_api_t apiHandle); #ifdef __cplusplus } -- cgit 1.2.3-korg