aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJonathan Aillet <jonathan.aillet@iot.bzh>2019-12-03 19:10:58 +0100
committerJonathan Aillet <jonathan.aillet@iot.bzh>2019-12-04 15:09:01 +0100
commit3dd9b3710a6724538c9b87581a1d7182808f3ba3 (patch)
tree5f8763f58db0021ffff01d08b3ec40e445121853
parentb39c6883f7d7d58d60178441c8d408118788418b (diff)
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 <jonathan.aillet@iot.bzh>
-rw-r--r--ctl-lib/ctl-config.c10
-rw-r--r--ctl-lib/ctl-lua.c4
-rw-r--r--ctl-lib/ctl-plugin.c336
-rw-r--r--ctl-lib/ctl-plugin.h3
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
}