aboutsummaryrefslogtreecommitdiffstats
path: root/ctl-lib
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 /ctl-lib
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>
Diffstat (limited to 'ctl-lib')
-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
}