aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ctl-lib/CMakeLists.txt2
-rw-r--r--ctl-lib/ctl-action.c6
-rw-r--r--ctl-lib/ctl-config.c5
-rw-r--r--ctl-lib/ctl-lua-utils.c87
-rw-r--r--ctl-lib/ctl-lua.c319
-rw-r--r--ctl-lib/ctl-lua.h8
-rw-r--r--ctl-lib/ctl-plugin.c234
-rw-r--r--ctl-lib/ctl-plugin.h5
8 files changed, 440 insertions, 226 deletions
diff --git a/ctl-lib/CMakeLists.txt b/ctl-lib/CMakeLists.txt
index 4f29014..3ab0774 100644
--- a/ctl-lib/CMakeLists.txt
+++ b/ctl-lib/CMakeLists.txt
@@ -19,7 +19,7 @@
# Include LUA only when requested
if(CONTROL_SUPPORT_LUA)
message(STATUS "Notice: LUA Controler Support Selected")
- set(CTL_LUA_SOURCE ctl-lua.c ctl-timer.c)
+ set(CTL_LUA_SOURCE ctl-lua.c ctl-timer.c ctl-lua-utils.c)
ADD_COMPILE_OPTIONS(-DCONTROL_SUPPORT_LUA)
else(CONTROL_SUPPORT_LUA)
message(STATUS "Warning: LUA Without Support ")
diff --git a/ctl-lib/ctl-action.c b/ctl-lib/ctl-action.c
index 277591d..da2eef1 100644
--- a/ctl-lib/ctl-action.c
+++ b/ctl-lib/ctl-action.c
@@ -24,8 +24,6 @@
#include "ctl-config.h"
-extern CtlLua2cFuncT *ctlLua2cFunc;
-
PUBLIC int ActionLabelToIndex(CtlActionT*actions, const char* actionLabel) {
for (int idx = 0; actions[idx].uid; idx++) {
if (!strcasecmp(actionLabel, actions[idx].uid)) return idx;
@@ -58,10 +56,6 @@ PUBLIC void ActionExecUID(AFB_ReqT request, CtlConfigT *ctlConfig, const char *u
PUBLIC void ActionExecOne(CtlSourceT *source, CtlActionT* action, json_object *queryJ) {
int err = 0;
- if(action->type == CTL_TYPE_LUA && ctlLua2cFunc && ctlLua2cFunc->l2cCount) {
- LuaL2cNewLib (ctlLua2cFunc->l2cFunc, ctlLua2cFunc->l2cCount);
- }
-
switch (action->type) {
case CTL_TYPE_API:
{
diff --git a/ctl-lib/ctl-config.c b/ctl-lib/ctl-config.c
index 6294f63..b811754 100644
--- a/ctl-lib/ctl-config.c
+++ b/ctl-lib/ctl-config.c
@@ -109,11 +109,6 @@ PUBLIC int CtlConfigExec(AFB_ApiT apiHandle, CtlConfigT *ctlConfig) {
}
}
-#ifdef CONTROL_SUPPORT_LUA
- int err = LuaConfigExec(apiHandle, ctlConfig->api);
- if (err) goto OnErrorExit;
-#endif
-
// Loop on every section and process config
int errcount=0;
for (int idx = 0; ctlConfig->sections[idx].key != NULL; idx++) {
diff --git a/ctl-lib/ctl-lua-utils.c b/ctl-lib/ctl-lua-utils.c
new file mode 100644
index 0000000..da22b7a
--- /dev/null
+++ b/ctl-lib/ctl-lua-utils.c
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2016 \"IoT.bzh\"
+ * Author Fulup Ar Foll <fulup@iot.bzh>
+ *
+ Licensed under the Apache License, Version 2.0 (the \"License\");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an \"AS IS\" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ref:
+ * (manual) https://www.lua.org/manual/5.3/manual.html
+ * (lua->C) http://www.troubleshooters.com/codecorn/lua/lua_c_calls_lua.htm#_Anatomy_of_a_Lua_Call
+ * (lua/C Var) http://acamara.es/blog/2012/08/passing-variables-from-lua-5-2-to-c-and-vice-versa/
+ * (Lua/C Lib)https://john.nachtimwald.com/2014/07/12/wrapping-a-c-library-in-lua/
+ * (Lua/C Table) https://gist.github.com/SONIC3D/10388137
+ * (Lua/C Nested table) https://stackoverflow.com/questions/45699144/lua-nested-table-from-lua-to-c
+ * (Lua/C Wrapper) https://stackoverflow.com/questions/45699950/lua-passing-handle-to-function-created-with-newlib
+ *
+ */
+
+const char *lua_utils = "--===================================================\n\
+--= Niklas Frykholm\n\
+-- basically if user tries to create global variable\n\
+-- the system will not let them!!\n\
+-- call GLOBAL_lock(_G)\n\
+-- \n\
+--===================================================\n\
+function GLOBAL_lock(t)\n\
+ local mt = getmetatable(t) or {}\n\
+ mt.__newindex = lock_new_index\n\
+ setmetatable(t, mt)\n\
+end\n\
+\n\
+--===================================================\n\
+-- call GLOBAL_unlock(_G)\n\
+-- to change things back to normal.\n\
+--===================================================\n\
+function GLOBAL_unlock(t)\n\
+ local mt = getmetatable(t) or {}\n\
+ mt.__newindex = unlock_new_index\n\
+ setmetatable(t, mt)\n\
+end\n\
+\n\
+function lock_new_index(t, k, v)\n\
+ if (string.sub(k,1,1) ~= \"_\") then\n\
+ GLOBAL_unlock(_G)\n\
+ error(\"GLOBALS are locked -- \" .. k ..\n\
+ \" must be declared local or prefix with '_' for globals.\", 2)\n\
+ else\n\
+ rawset(t, k, v)\n\
+ end\n\
+end\n\
+\n\
+function unlock_new_index(t, k, v)\n\
+ rawset(t, k, v)\n\
+end\n\
+\n\
+-- return serialised version of printable table\n\
+function Dump_Table(o)\n\
+ if type(o) == 'table' then\n\
+ local s = '{ '\n\
+ for k,v in pairs(o) do\n\
+ if type(k) ~= 'number' then k = '\"'..k..'\"' end\n\
+ s = s .. '['..k..'] = ' .. Dump_Table(v) .. ','\
+ end\n\
+ return s .. '} '\n\
+ else\n\
+ return tostring(o)\n\
+ end\n\
+end\n\
+\n\
+-- simulate C prinf function\n\
+printf = function(s,...)\n\
+ io.write(s:format(...))\n\
+ io.write(\"\")\n\
+ return\n\
+end\n\
+\n\
+-- lock global variable\n\
+GLOBAL_lock(_G)\n\
+";
diff --git a/ctl-lib/ctl-lua.c b/ctl-lib/ctl-lua.c
index 757956e..d5c2975 100644
--- a/ctl-lib/ctl-lua.c
+++ b/ctl-lib/ctl-lua.c
@@ -36,6 +36,7 @@
#define JSON_ERROR (json_object*)-1
+extern CtlLua2cFuncT *ctlLua2cFunc;
static lua_State* luaState;
#ifndef CTX_MAGIC
@@ -299,7 +300,7 @@ STATIC int LuaFormatMessage(lua_State* luaState, int verbosity, int level) {
const char *format = json_object_get_string(json_object_array_get_idx(responseJ, 0));
int arrayIdx=1;
- int targetIdx=0;
+ int uidIdx=0;
for (int idx=0; format[idx] !='\0'; idx++) {
@@ -310,43 +311,43 @@ STATIC int LuaFormatMessage(lua_State* luaState, int verbosity, int level) {
switch (format[++idx]) {
case 'd':
- if (slotJ) targetIdx += snprintf (&message[targetIdx], LUA_MSG_MAX_LENGTH-targetIdx,"%d", json_object_get_int(slotJ));
- else targetIdx += snprintf (&message[targetIdx], LUA_MSG_MAX_LENGTH-targetIdx,"nil");
+ if (slotJ) uidIdx += snprintf (&message[uidIdx], LUA_MSG_MAX_LENGTH-uidIdx,"%d", json_object_get_int(slotJ));
+ else uidIdx += snprintf (&message[uidIdx], LUA_MSG_MAX_LENGTH-uidIdx,"nil");
arrayIdx++;
break;
case 'f':
- if (slotJ) targetIdx += snprintf (&message[targetIdx], LUA_MSG_MAX_LENGTH-targetIdx,"%f", json_object_get_double(slotJ));
- else targetIdx += snprintf (&message[targetIdx], LUA_MSG_MAX_LENGTH-targetIdx,"nil");
+ if (slotJ) uidIdx += snprintf (&message[uidIdx], LUA_MSG_MAX_LENGTH-uidIdx,"%f", json_object_get_double(slotJ));
+ else uidIdx += snprintf (&message[uidIdx], LUA_MSG_MAX_LENGTH-uidIdx,"nil");
arrayIdx++;
break;
case'%':
- message[targetIdx]='%';
- targetIdx++;
+ message[uidIdx]='%';
+ uidIdx++;
break;
case 'A':
- targetIdx += snprintf (&message[targetIdx], LUA_MSG_MAX_LENGTH-targetIdx,"level: %s", source->uid);
+ uidIdx += snprintf (&message[uidIdx], LUA_MSG_MAX_LENGTH-uidIdx,"level: %s", source->uid);
break;
case 's':
default:
- if (slotJ) targetIdx += snprintf (&message[targetIdx], LUA_MSG_MAX_LENGTH-targetIdx,"%s", json_object_get_string(slotJ));
- else targetIdx += snprintf (&message[targetIdx], LUA_MSG_MAX_LENGTH-targetIdx,"nil");
+ if (slotJ) uidIdx += snprintf (&message[uidIdx], LUA_MSG_MAX_LENGTH-uidIdx,"%s", json_object_get_string(slotJ));
+ else uidIdx += snprintf (&message[uidIdx], LUA_MSG_MAX_LENGTH-uidIdx,"nil");
arrayIdx++;
}
} else {
- if (targetIdx >= LUA_MSG_MAX_LENGTH) {
+ if (uidIdx >= LUA_MSG_MAX_LENGTH) {
AFB_ApiWarning (source->api, "LuaFormatMessage: message[%s] owerverflow LUA_MSG_MAX_LENGTH=%d", format, LUA_MSG_MAX_LENGTH);
- targetIdx --; // move backward for EOL
+ uidIdx --; // move backward for EOL
break;
} else {
- message[targetIdx++] = format[idx];
+ message[uidIdx++] = format[idx];
}
}
}
- message[targetIdx]='\0';
+ message[uidIdx]='\0';
PrintMessage:
// TBD: __file__ and __line__ should match LUA source code
@@ -695,10 +696,10 @@ PUBLIC int LuaCallFunc (CtlSourceT *source, CtlActionT *action, json_object *que
int err, count;
- json_object* argsJ = action->argsJ;
- const char* func = action->exec.lua.funcname;
+ json_object* argsJ = action->argsJ;
+ const char* func = action->exec.lua.funcname;
- // load function (should exist in CONTROL_PATH_LUA
+ // load function (should exist in CONTROL_PATH_LUA)
lua_getglobal(luaState, func);
// push source on the stack
@@ -737,145 +738,178 @@ PUBLIC int LuaCallFunc (CtlSourceT *source, CtlActionT *action, json_object *que
return -1;
}
+PUBLIC int luaLoadScript(const char *luaScriptPath)
+{
+ int err = luaL_loadfile(luaState, luaScriptPath);
+ if (err) {
+ AFB_ApiError(source->api, "LUA-DOSCRIPT HOOPs Error in LUA loading scripts=%s err=%s", luaScriptPath, lua_tostring(luaState,-1));
+ return err;
+ }
-// Execute LUA code from received API request
-STATIC void LuaDoAction (LuaDoActionT action, AFB_ReqT request) {
+ // Script was loaded we need to parse to make it executable
+ err = lua_pcall(luaState, 0, 0, 0);
+ if (err) {
+ AFB_ApiError(source->api, "LUA-DOSCRIPT:FAIL to load %s", luaScriptPath);
+ return err;
+ }
- int err, count=0;
- CtlSourceT *source = alloca(sizeof(CtlSourceT));
- source->request = request;
+ return err;
+}
- json_object* queryJ = AFB_ReqJson(request);
+STATIC int LuaDoScript(json_object *queryJ, CtlSourceT *source)
+{
+ const char *uid = NULL, *func = NULL;
+ char luaScriptPath[CONTROL_MAXPATH_LEN];
+ char *filename, *fullpath;
+ int index, err = 0;
+ json_object *argsJ=NULL;
+ static json_object *luaScriptPathJ = NULL;
+ if (!queryJ) {
+ return -1;
+ }
- switch (action) {
+ err= wrap_json_unpack (queryJ, "{s:s,s?s,s?s,s?o !}",
+ "uid", &uid,
+ "spath",&luaScriptPathJ,
+ "function",&func,
+ "args",&argsJ);
- case LUA_DOSTRING: {
- const char *script = json_object_get_string(queryJ);
- err=luaL_loadstring(luaState, script);
- if (err) {
- AFB_ApiError(source->api, "LUA-DO-COMPILE:FAIL String=%s err=%s", script, lua_tostring(luaState,-1) );
- goto OnErrorExit;
- }
- // Push AFB client context on the stack
- LuaAfbSourceT *afbSource= LuaSourcePush(luaState, source);
- if (!afbSource) goto OnErrorExit;
+ if (err) {
+ return -1;
+ }
- break;
+ // search for filename=script in CONTROL_LUA_PATH
+ if (!luaScriptPathJ) {
+ strncpy(luaScriptPath,CONTROL_DOSCRIPT_PRE, strlen(CONTROL_DOSCRIPT_PRE)+1);
+ strncat(luaScriptPath,"-", strlen("-"));
+ strncat(luaScriptPath,uid, strlen(uid));
+ luaScriptPathJ= ScanForConfig(luaScriptPath , CTL_SCAN_RECURSIVE, luaScriptPath, ".lua");
+ }
+
+ for (index=0; index < json_object_array_length(luaScriptPathJ); index++) {
+ json_object *entryJ=json_object_array_get_idx(luaScriptPathJ, index);
+
+ err= wrap_json_unpack (entryJ, "{s:s, s:s !}", "fullpath", &fullpath,"filename", &filename);
+ if (err) {
+ AFB_ApiError(source->api, "LUA-DOSCRIPT-SCAN:HOOPs invalid config file path = %s", json_object_get_string(entryJ));
+ return -2;
}
- case LUA_DOCALL: {
- const char *func;
- json_object *argsJ=NULL;
+ // Ignoring other found script. Only take the first one.
+ if (!index) {
+ strncpy (luaScriptPath, fullpath, strlen(fullpath)+1);
+ strncat (luaScriptPath, "/", strlen("/"));
+ strncat (luaScriptPath, filename, strlen(filename));
+ }
+ }
- err= wrap_json_unpack (queryJ, "{s:s, s?o !}", "target", &func, "args", &argsJ);
- if (err) {
- AFB_ApiError(source->api, "LUA-DOCALL-SYNTAX missing target|args query=%s", json_object_get_string(queryJ));
- goto OnErrorExit;
- }
+ err = luaLoadScript(luaScriptPath);
+ if(err)
+ return err;
- // load function (should exist in CONTROL_PATH_LUA
- lua_getglobal(luaState, func);
+ // if no func name given try to deduct from filename
+ if (!func && (func=(char*)GetMidleName(filename))!=NULL) {
+ strncpy(luaScriptPath,"_", strlen("_")+1);
+ strncat(luaScriptPath,func, strlen(func));
+ func=luaScriptPath;
+ }
+ if (!func) {
+ AFB_ApiError(source->api, "LUA-DOSCRIPT:FAIL to deduct funcname from %s", filename);
+ return -5;
+ }
- // Push AFB client context on the stack
- LuaAfbSourceT *afbSource= LuaSourcePush(luaState, source);
- if (!afbSource) goto OnErrorExit;
+ // load function (should exist in CONTROL_PATH_LUA
+ lua_getglobal(luaState, func);
- // push query on the stack
- if (!argsJ) {
- lua_pushnil(luaState);
- count++;
- } else {
- count+= LuaPushArgument (source, argsJ);
- }
+ // Push AFB client context on the stack
+ LuaAfbSourceT *afbSource = LuaSourcePush(luaState, source);
+ if (!afbSource)
+ return -6;
- break;
- }
+ return 0;
+}
- case LUA_DOSCRIPT: { // Fulup need to fix argument passing
- char *filename; char*fullpath;
- char luaScriptPath[CONTROL_MAXPATH_LEN];
- int index;
-
- // scan luascript search path once
- static json_object *luaScriptPathJ =NULL;
-
- // extract value from query
- const char *target=NULL,*func=NULL;
- json_object *argsJ=NULL;
- err= wrap_json_unpack (queryJ, "{s:s,s?s,s?s,s?o !}",
- "target", &target,
- "path",&luaScriptPathJ,
- "function",&func,
- "args",&argsJ);
- if (err) {
- AFB_ApiError(source->api, "LUA-DOSCRIPT-SYNTAX:missing target|[path]|[function]|[args] query=%s", json_object_get_string(queryJ));
- goto OnErrorExit;
- }
+STATIC int LuaDoCall(json_object *queryJ, CtlSourceT *source)
+{
+ int err = 0;
+ int count = 0;
+ const char *func;
+ json_object *argsJ = NULL;
- // search for filename=script in CONTROL_LUA_PATH
- if (!luaScriptPathJ) {
- strncpy(luaScriptPath,CONTROL_DOSCRIPT_PRE, strlen(CONTROL_DOSCRIPT_PRE)+1);
- strncat(luaScriptPath,"-", strlen("-"));
- strncat(luaScriptPath,target, strlen(target));
- luaScriptPathJ= ScanForConfig(CONTROL_LUA_PATH , CTL_SCAN_RECURSIVE,luaScriptPath,".lua");
- }
- for (index=0; index < json_object_array_length(luaScriptPathJ); index++) {
- json_object *entryJ=json_object_array_get_idx(luaScriptPathJ, index);
+ if(!queryJ)
+ return -1;
- err= wrap_json_unpack (entryJ, "{s:s, s:s !}", "fullpath", &fullpath,"filename", &filename);
- if (err) {
- AFB_ApiError(source->api, "LUA-DOSCRIPT-SCAN:HOOPs invalid config file path = %s", json_object_get_string(entryJ));
- goto OnErrorExit;
- }
+ err = wrap_json_unpack(queryJ, "{s:s, s?o !}", "uid", &func, "args", &argsJ);
+ if (err)
+ return -2;
- if (index > 0) AFB_ApiWarning(source->api, "LUA-DOSCRIPT-SCAN:Ignore second script=%s path=%s", filename, fullpath);
- else {
- strncpy (luaScriptPath, fullpath, strlen(fullpath)+1);
- strncat (luaScriptPath, "/", strlen("/"));
- strncat (luaScriptPath, filename, strlen(filename));
- }
- }
+ // load function (should exist in CONTROL_PATH_LUA
+ lua_getglobal(luaState, func);
- err= luaL_loadfile(luaState, luaScriptPath);
- if (err) {
- AFB_ApiError(source->api, "LUA-DOSCRIPT HOOPs Error in LUA loading scripts=%s err=%s", luaScriptPath, lua_tostring(luaState,-1));
- goto OnErrorExit;
- }
+ // Push AFB client context on the stack
+ LuaAfbSourceT *afbSource= LuaSourcePush(luaState, source);
+ if (!afbSource)
+ return -3;
- // script was loaded we need to parse to make it executable
- err=lua_pcall(luaState, 0, 0, 0);
- if (err) {
- AFB_ApiError(source->api, "LUA-DOSCRIPT:FAIL to load %s", luaScriptPath);
- goto OnErrorExit;
- }
+ // push query on the stack
+ if (!argsJ) {
+ lua_pushnil(luaState);
+ count++;
+ } else {
+ count+= LuaPushArgument (source, argsJ);
+ }
- // if no func name given try to deduct from filename
- if (!func && (func=(char*)GetMidleName(filename))!=NULL) {
- strncpy(luaScriptPath,"_", strlen("_")+1);
- strncat(luaScriptPath,func, strlen(func));
- func=luaScriptPath;
- }
- if (!func) {
- AFB_ApiError(source->api, "LUA-DOSCRIPT:FAIL to deduct funcname from %s", filename);
- goto OnErrorExit;
- }
+ return count;
+}
- // load function (should exist in CONTROL_PATH_LUA
- lua_getglobal(luaState, func);
+STATIC int LuaDoString(const char *script, CtlSourceT *source)
+{
+ int err = 0;
- // Push AFB client context on the stack
- LuaAfbSourceT *afbSource= LuaSourcePush(luaState, source);
- if (!afbSource) goto OnErrorExit;
+ err = luaL_loadstring(luaState, script);
+ if (err)
+ return -1;
- // push function arguments
- if (!argsJ) {
- lua_pushnil(luaState);
- count++;
- } else {
- count+= LuaPushArgument(source, argsJ);
- }
+ // Push AFB client context on the stack
+ if(source) {
+ LuaAfbSourceT *afbSource= LuaSourcePush(luaState, source);
+ if (!afbSource)
+ return -2;
+ }
+ return 0;
+}
+
+// Execute LUA code from received API request
+STATIC void LuaDoAction (LuaDoActionT action, AFB_ReqT request) {
+ int err, count=0;
+ CtlSourceT *source = alloca(sizeof(CtlSourceT));
+ source->request = request;
+
+ json_object* queryJ = AFB_ReqJson(request);
+
+ switch (action) {
+
+ case LUA_DOSTRING: {
+ const char *script = json_object_get_string(queryJ);
+ count = LuaDoString(script, source);
+ if(count)
+ AFB_ApiError(source->api, "DOSTRING goes wrong err=%d, String=%s ", count, script);
+ break;
+ }
+
+ case LUA_DOCALL: {
+ count = LuaDoCall(queryJ, source);
+ if(count)
+ AFB_ApiError(source->api, "DOCALL goes wrong, error = %d, query=%s", count, json_object_get_string(queryJ));
+ break;
+ }
+
+ case LUA_DOSCRIPT: { // Fulup need to fix argument passing
+ count = LuaDoScript(queryJ, source);
+ if(count)
+ AFB_ApiError(source->api, "DOSCRIPT goes wrong error=%d query=%s", count, json_object_get_string(queryJ));
break;
}
@@ -884,8 +918,8 @@ STATIC void LuaDoAction (LuaDoActionT action, AFB_ReqT request) {
goto OnErrorExit;
}
- // effectively exec LUA code (afb_reply/fail done later from callback)
- err=lua_pcall(luaState, count+1, 0, 0);
+ if(count >= 0)
+ err=lua_pcall(luaState, count+1, 0, 0);
if (err) {
AFB_ApiError(source->api, "LUA-DO-EXEC:FAIL query=%s err=%s", json_object_get_string(queryJ), lua_tostring(luaState,-1));
goto OnErrorExit;
@@ -1214,7 +1248,7 @@ PUBLIC void LuaL2cNewLib(luaL_Reg *l2cFunc, int count) {
luaL_checkversion(luaState);
lua_createtable(luaState, 0, count+1);
luaL_setfuncs(luaState,l2cFunc,0);
- lua_setglobal(luaState, "_lua2c");
+ lua_setglobal(luaState, "L2C");
}
static const luaL_Reg afbFunction[] = {
@@ -1242,7 +1276,8 @@ static const luaL_Reg afbFunction[] = {
// Load Lua Interpreter
PUBLIC int LuaConfigLoad (AFB_ApiT apiHandle) {
- static int luaLoaded=0;
+ static int luaLoaded=0, err = 0;
+ //int err = 0;
// Lua loads only once
if (luaLoaded) return 0;
@@ -1271,6 +1306,13 @@ PUBLIC int LuaConfigLoad (AFB_ApiT apiHandle) {
TIMER_MAGIC=CtlConfigMagicNew();
#endif
+ // Load LUA utils functions.
+ err = LuaDoString(lua_utils, NULL);
+ if(err) {
+ AFB_ApiError(apiHandle, "Error loading lua_utils default functions.%s, %d", lua_utils, err);
+ return -1;
+ }
+
return 0;
OnErrorExit:
@@ -1283,6 +1325,11 @@ PUBLIC int LuaConfigExec (AFB_ApiT apiHandle, const char* prefix) {
int err, index;
+ // create L2C mapping before any LUA script is loaded
+ if (ctlLua2cFunc && ctlLua2cFunc->l2cCount) {
+ LuaL2cNewLib (ctlLua2cFunc->l2cFunc, ctlLua2cFunc->l2cCount);
+ }
+
// search for default policy config files
char fullprefix[CONTROL_MAXPATH_LEN] = "";
if(prefix)
@@ -1293,7 +1340,7 @@ PUBLIC int LuaConfigExec (AFB_ApiT apiHandle, const char* prefix) {
strncat (fullprefix, "-", strlen("-"));
const char *dirList= getenv("CONTROL_LUA_PATH");
- if (!dirList) dirList=CONTROL_LUA_PATH;
+ //if (!dirList) dirList=CONTROL_LUA_PATH;
// special case for no lua even when avaliable
if (!strcasecmp ("/dev/null", dirList)) {
diff --git a/ctl-lib/ctl-lua.h b/ctl-lib/ctl-lua.h
index b3aea54..cf28dcb 100644
--- a/ctl-lib/ctl-lua.h
+++ b/ctl-lib/ctl-lua.h
@@ -39,11 +39,6 @@ extern "C" {
#define CONTROL_LUA_EVENT "luaevt"
#endif
-// default use same search path for config.json and script.lua
-#ifndef CONTROL_LUA_PATH
-#define CONTROL_LUA_PATH CONTROL_CONFIG_PATH
-#endif
-
// standard lua include file
#ifdef CONTROL_SUPPORT_LUA
#include "lua.h"
@@ -62,7 +57,8 @@ typedef enum {
LUA_DOSCRIPT,
} LuaDoActionT;
-
+extern const char *lua_utils;
+PUBLIC int luaLoadScript(const char *luaScriptPath);
PUBLIC int LuaConfigLoad (AFB_ApiT apiHandle);
PUBLIC int LuaConfigExec(AFB_ApiT apiHandle, const char * prefix);
PUBLIC void LuaL2cNewLib(luaL_Reg *l2cFunc, int count);
diff --git a/ctl-lib/ctl-plugin.c b/ctl-lib/ctl-plugin.c
index 2520d77..3e3e16e 100644
--- a/ctl-lib/ctl-plugin.c
+++ b/ctl-lib/ctl-plugin.c
@@ -84,77 +84,19 @@ STATIC int DispatchOneL2c(void* luaState, char *funcname, Lua2cFunctionT callbac
#endif
}
-STATIC int PluginLoadOne (AFB_ApiT apiHandle, CtlPluginT *ctlPlugin, json_object *pluginJ, void* handle) {
- json_object *lua2csJ = NULL, *pluginPathJ = NULL;
- const char*ldSearchPath = NULL, *basename = NULL;
- void *dlHandle;
+STATIC int PluginLoadCOne(AFB_ApiT apiHandle, const char *pluginpath, json_object *lua2csJ, void * handle, CtlPluginT *ctlPlugin)
+{
+ void *dlHandle = dlopen(pluginpath, RTLD_NOW);
-
- // plugin initialises at 1st load further init actions should be place into onload section
- if (!pluginJ) return 0;
-
- int err = wrap_json_unpack(pluginJ, "{ss,s?s,s?s,s?s,s?o !}",
- "uid", &ctlPlugin->uid,
- "info", &ctlPlugin->info,
- "ldpath", &ldSearchPath,
- "basename", &basename,
- "lua2c", &lua2csJ);
- if (err) {
- AFB_ApiError(apiHandle, "CTL-PLUGIN-LOADONE Plugin missing uid|[info]|basename|[ldpath]|[lua2c] in:\n-- %s", json_object_get_string(pluginJ));
- goto OnErrorExit;
- }
-
- // default basename equal uid
- if (!basename) basename=ctlPlugin->uid;
-
- // if search path not in Json config file, then try default
- if (!ldSearchPath)
- {
- char path[CONTROL_MAXPATH_LEN];
- memset(path, 0, sizeof(path));
- const char *envpath = getenv("CONTROL_PLUGIN_PATH");
- envpath ?
- strncat(path, envpath, strlen(envpath)):
- strncat(path, CONTROL_PLUGIN_PATH, strlen(CONTROL_PLUGIN_PATH));
- const char *bPath = GetBindingDirPath();
- strncat(path, ":", strlen(":"));
- strncat(path, bPath, strlen(bPath));
- ldSearchPath = path;
- }
-
- // search for default policy config file
- pluginPathJ = ScanForConfig(ldSearchPath, CTL_SCAN_RECURSIVE, basename, CTL_PLUGIN_EXT);
- if (!pluginPathJ || json_object_array_length(pluginPathJ) == 0) {
- AFB_ApiError(apiHandle, "CTL-PLUGIN-LOADONE Missing plugin=%s*%s (config ldpath?) search=\n-- %s", basename, CTL_PLUGIN_EXT, ldSearchPath);
- goto OnErrorExit;
- }
-
- char *filename;
- char*fullpath;
- err = wrap_json_unpack(json_object_array_get_idx(pluginPathJ, 0), "{s:s, s:s !}", "fullpath", &fullpath, "filename", &filename);
- if (err) {
- AFB_ApiError(apiHandle, "CTL-PLUGIN-LOADONE HOOPs invalid plugin file path=\n-- %s", json_object_get_string(pluginPathJ));
- goto OnErrorExit;
- }
-
- if (json_object_array_length(pluginPathJ) > 1) {
- AFB_ApiWarning(apiHandle, "CTL-PLUGIN-LOADONE plugin multiple instances in searchpath will use %s/%s", fullpath, filename);
- }
-
- char pluginpath[CONTROL_MAXPATH_LEN];
- strncpy(pluginpath, fullpath, strlen (fullpath)+1);
- strncat(pluginpath, "/", strlen ("/"));
- strncat(pluginpath, filename, strlen (filename));
- dlHandle = dlopen(pluginpath, RTLD_NOW);
if (!dlHandle) {
AFB_ApiError(apiHandle, "CTL-PLUGIN-LOADONE Fail to load pluginpath=%s err= %s", pluginpath, dlerror());
- goto OnErrorExit;
+ return -1;
}
CtlPluginMagicT *ctlPluginMagic = (CtlPluginMagicT*) dlsym(dlHandle, "CtlPluginMagic");
if (!ctlPluginMagic || ctlPluginMagic->magic != CTL_PLUGIN_MAGIC) {
AFB_ApiError(apiHandle, "CTL-PLUGIN-LOADONE symbol'CtlPluginMagic' missing or != CTL_PLUGIN_MAGIC plugin=%s", pluginpath);
- goto OnErrorExit;
+ return -1;
} else {
AFB_ApiNotice(apiHandle, "CTL-PLUGIN-LOADONE %s successfully registered", ctlPluginMagic->uid);
}
@@ -175,7 +117,7 @@ STATIC int PluginLoadOne (AFB_ApiT apiHandle, CtlPluginT *ctlPlugin, json_object
#else
// Lua2cWrapper is part of binder and not expose to dynamic link
if (lua2csJ && lua2cInPlug) {
- *lua2cInPlug = DispatchOneL2c;
+ *lua2cInPlug = (Lua2cWrapperT)DispatchOneL2c;
int Lua2cAddOne(luaL_Reg *l2cFunc, const char* l2cName, int index) {
if(ctlLua2cFunc->l2cCount)
@@ -219,7 +161,7 @@ STATIC int PluginLoadOne (AFB_ApiT apiHandle, CtlPluginT *ctlPlugin, json_object
}
if (errCount) {
AFB_ApiError(apiHandle, "CTL-PLUGIN-LOADONE %d symbols not found in plugin='%s'", errCount, pluginpath);
- goto OnErrorExit;
+ return -1;
}
int total = ctlLua2cFunc->l2cCount + count;
if(ctlLua2cFunc->l2cCount) {
@@ -240,21 +182,171 @@ STATIC int PluginLoadOne (AFB_ApiT apiHandle, CtlPluginT *ctlPlugin, json_object
ctlPlugin->context = (*ctlPluginOnload) (ctlPlugin, handle);
}
+ return 0;
+}
+
+STATIC int LoadFoundPlugins(AFB_ApiT apiHandle, json_object *scanResult, json_object *lua2csJ, void *handle, CtlPluginT *ctlPlugin)
+{
+ char pluginpath[CONTROL_MAXPATH_LEN];
+ char *filename;
+ char *fullpath;
+ char *ext;
+ int i;
+ size_t len;
+ json_object *object = NULL;
+
+ if (!json_object_is_type(scanResult, json_type_array))
+ return -1;
+
+ len = json_object_array_length(scanResult);
+
+ for (i = 0; i < len; ++i) {
+ object = json_object_array_get_idx(scanResult, i);
+ int err = wrap_json_unpack(object, "{s:s, s:s !}",
+ "fullpath", &fullpath,
+ "filename", &filename);
+
+ if (err) {
+ AFB_ApiError(apiHandle, "HOOPs invalid plugin file path=\n-- %s", json_object_get_string(scanResult));
+ return -1;
+ }
+
+ /* Make sure you don't load two found libraries */
+ ext = strrchr(filename, '.');
+ strncpy(pluginpath, fullpath, strlen (fullpath)+1);
+ strncat(pluginpath, "/", strlen ("/"));
+ strncat(pluginpath, filename, strlen (filename));
+
+ if(!strcasecmp(ext, CONTROL_PLUGIN_EXT)) {
+ if(ext && !strcasecmp(ext, CONTROL_PLUGIN_EXT) && i > 0) {
+ AFB_ApiWarning(apiHandle, "Plugin multiple instances in searchpath will use %s/%s", fullpath, filename);
+ return 0;
+ }
+ PluginLoadCOne(apiHandle, pluginpath, lua2csJ, handle, ctlPlugin);
+ }
+ else if(!strcasecmp(ext, CONTROL_SCRIPT_EXT)) {
+ ctlPlugin->api = apiHandle;
+ ctlPlugin->context = handle;
+ luaLoadScript(pluginpath);
+ }
+ }
+
+ return 0;
+}
+
+STATIC char *GetDefaultSearchPath()
+{
+ char *searchPath;
+ const char *bPath;
+ const char *envPath;
+ size_t bPath_len, envPath_len, CTL_PLGN_len;
+
+ bPath = GetBindingDirPath();
+ envPath = getenv("CONTROL_PLUGIN_PATH");
+ bPath_len = strlen(bPath);
+ envPath_len = envPath ? strlen(envPath) : 0;
+ CTL_PLGN_len = envPath_len ? 0 : strlen(CONTROL_PLUGIN_PATH);
+
+ /* Allocating with the size of binding root dir path + environment if found
+ * + 2 for the NULL terminating character and the additionnal separator
+ * between bPath and envPath concatenation.
+ */
+ if(envPath) {
+ searchPath = calloc(1, sizeof(char) *((bPath_len + envPath_len) + 2));
+ strncat(searchPath, envPath, envPath_len);
+ }
+ else {
+ searchPath = calloc(1, sizeof(char) * ((bPath_len + CTL_PLGN_len) + 2));
+ strncat(searchPath, CONTROL_PLUGIN_PATH, CTL_PLGN_len);
+ }
+
+ strncat(searchPath, ":", 1);
+ strncat(searchPath, bPath, bPath_len);
+
+ return searchPath;
+}
+
+STATIC int FindPlugins(AFB_ApiT apiHandle, const char *searchPath, const char *file, json_object **pluginPathJ)
+{
+ *pluginPathJ = ScanForConfig(searchPath, CTL_SCAN_RECURSIVE, file, NULL);
+ if (!*pluginPathJ || json_object_array_length(*pluginPathJ) == 0) {
+ AFB_ApiError(apiHandle, "CTL-PLUGIN-LOADONE Missing plugin=%s* (config ldpath?) search=\n-- %s", file, searchPath);
+ return -1;
+ }
+
+ return 0;
+}
+
+STATIC int PluginLoad (AFB_ApiT apiHandle, CtlPluginT *ctlPlugin, json_object *pluginJ, void *handle)
+{
+ int err = 0, i = 0;
+ char *searchPath;
+ const char *sPath = NULL, *file = NULL;
+ json_object *lua2csJ = NULL, *fileJ = NULL, *pluginPathJ = NULL;
+
+ // plugin initialises at 1st load further init actions should be place into onload section
+ if (!pluginJ) return 0;
+
+ err = wrap_json_unpack(pluginJ, "{ss,s?s,s?s,s?o,s?o !}",
+ "uid", &ctlPlugin->uid,
+ "info", &ctlPlugin->info,
+ "spath", &sPath,
+ "file", &fileJ,
+ "lua2c", &lua2csJ);
+ if (err) {
+ AFB_ApiError(apiHandle, "CTL-PLUGIN-LOADONE Plugin missing uid|[info]|file|[ldpath]|[lua2c] in:\n-- %s", json_object_get_string(pluginJ));
+ goto OnErrorExit;
+ }
+
+ // if search path not in Json config file, then try default
+ if(sPath)
+ searchPath = strdup(sPath);
+ else
+ searchPath = GetDefaultSearchPath();
+
+ // default file equal uid
+ if (!fileJ) {
+ file = ctlPlugin->uid;
+ if(FindPlugins(apiHandle, searchPath, file, &pluginPathJ))
+ goto OnErrorExit;
+ LoadFoundPlugins(apiHandle, pluginPathJ, lua2csJ, handle, ctlPlugin);
+ }
+ else if(json_object_is_type(fileJ, json_type_string)) {
+ file = json_object_get_string(fileJ);
+ if(FindPlugins(apiHandle, searchPath, file, &pluginPathJ))
+ goto OnErrorExit;
+ LoadFoundPlugins(apiHandle, pluginPathJ, lua2csJ, handle, ctlPlugin);
+ }
+ else if(json_object_is_type(fileJ, json_type_array)) {
+ for(i = 0; i < json_object_array_length(fileJ);++i) {
+ file = json_object_get_string(json_object_array_get_idx(fileJ, i));
+ if(FindPlugins(apiHandle, searchPath, file, &pluginPathJ))
+ goto OnErrorExit;
+ LoadFoundPlugins(apiHandle, pluginPathJ, lua2csJ, handle, ctlPlugin);
+ }
+ }
+
+ if(err)
+ goto OnErrorExit;
+
+ free(searchPath);
json_object_put(pluginPathJ); // No more needs for that json_object.
return 0;
OnErrorExit:
+ free(searchPath);
json_object_put(pluginPathJ); // No more needs for that json_object.
return 1;
}
PUBLIC int PluginConfig(AFB_ApiT apiHandle, CtlSectionT *section, json_object *pluginsJ) {
- int err=0;
+ int err = 0;
+ int idx = 0;
+ size_t length = 0;
if (ctlPlugins)
{
- int idx = 0;
while(ctlPlugins[idx].uid != NULL)
{
// Jose hack to make verbosity visible from sharedlib and
@@ -267,15 +359,15 @@ PUBLIC int PluginConfig(AFB_ApiT apiHandle, CtlSectionT *section, json_object *p
else
{
if (json_object_get_type(pluginsJ) == json_type_array) {
- size_t length = json_object_array_length(pluginsJ);
+ length = json_object_array_length(pluginsJ);
ctlPlugins = calloc (length+1, sizeof(CtlPluginT));
- for (int idx=0; idx < length; idx++) {
+ for (idx=0; idx < length; idx++) {
json_object *pluginJ = json_object_array_get_idx(pluginsJ, idx);
- err += PluginLoadOne(apiHandle, &ctlPlugins[idx], pluginJ, section->handle);
+ err += PluginLoad(apiHandle, &ctlPlugins[idx], pluginJ, section->handle);
}
} else {
ctlPlugins = calloc (2, sizeof(CtlPluginT));
- err += PluginLoadOne(apiHandle, &ctlPlugins[0], pluginsJ, section->handle);
+ err += PluginLoad(apiHandle, &ctlPlugins[0], pluginsJ, section->handle);
}
}
diff --git a/ctl-lib/ctl-plugin.h b/ctl-lib/ctl-plugin.h
index eaceea5..5d505ac 100644
--- a/ctl-lib/ctl-plugin.h
+++ b/ctl-lib/ctl-plugin.h
@@ -30,6 +30,9 @@ extern "C" {
#include <json-c/json.h>
+#define CONTROL_PLUGIN_EXT ".ctlso"
+#define CONTROL_SCRIPT_EXT ".lua"
+
// Waiting for a clean AppFW-V3 API
#ifdef USE_API_DYN
#define AFB_BINDING_VERSION dyn
@@ -212,7 +215,7 @@ typedef struct {
} subcall;
struct {
- const char* load;
+ const char* plugin;
const char* funcname;
} lua;