diff mbox series

[2/2] Introduce Handlers installable as plugin at runtime

Message ID 20240315092514.485906-2-stefano.babic@swupdate.org
State Accepted
Headers show
Series [1/2] handler: add function to unregister the handler | expand

Commit Message

Stefano Babic March 15, 2024, 9:25 a.m. UTC
The project supports Lua as script language for pre- and postinstall
script. This allows to install per update session Lua handlers
at run-time allowing to expand SWUpdate to the cases not covered
in the design phase of a product.

Signed-off-by: Stefano Babic <stefano.babic@swupdate.org>
---
 core/installer.c        |  1 +
 core/swupdate.c         |  2 +-
 corelib/lua_interface.c | 99 ++++++++++++++++++++++++++++-------------
 include/lua_util.h      |  4 +-
 4 files changed, 71 insertions(+), 35 deletions(-)

--
2.34.1
diff mbox series

Patch

diff --git a/core/installer.c b/core/installer.c
index f2fbbcab..48c7fe5e 100644
--- a/core/installer.c
+++ b/core/installer.c
@@ -483,6 +483,7 @@  void cleanup_files(struct swupdate_cfg *software) {
 	 * Drop Lua State if instantiated
 	 */
 	if (software->lua_state) {
+		unregister_session_handlers();
 		lua_exit(software->lua_state);
 		software->lua_state = NULL;
 	}
diff --git a/core/swupdate.c b/core/swupdate.c
index 140dec5e..a421e888 100644
--- a/core/swupdate.c
+++ b/core/swupdate.c
@@ -854,7 +854,7 @@  int main(int argc, char **argv)
 		}
 	}

-	lua_handlers_init();
+	lua_handlers_init(NULL);

 	if(!get_hw_revision(&swcfg.hw))
 		INFO("Running on %s Revision %s", swcfg.hw.boardname, swcfg.hw.revision);
diff --git a/corelib/lua_interface.c b/corelib/lua_interface.c
index 90aba6eb..03b74aed 100644
--- a/corelib/lua_interface.c
+++ b/corelib/lua_interface.c
@@ -1320,56 +1320,65 @@  static int l_handler_wrapper(struct img_type *img, void *data,
 	int res = 0;
 	lua_Number result;
 	int l_func_ref;
+	lua_State *L;
+	struct installer_handler *hnd;
+	hnd = find_handler(img);

-	if (!gL || !img || !data) {
+	if (!gL || !img || !data || !hnd) {
 		return -1;
 	}

+	if (hnd->noglobal) {
+		L = img->L;
+	} else {
+		L = gL;
+	}
+
 	if (img->bootloader) {
-		lua_getglobal(gL, "swupdate");
-		if (!lua_istable(gL, -1)) {
+		lua_getglobal(L, "swupdate");
+		if (!lua_istable(L, -1)) {
 			ERROR("Lua stack corrupted.");
 			return -1;
 		}
-		struct dict **udbootenv = lua_newuserdata(gL, sizeof(struct dict*));
+		struct dict **udbootenv = lua_newuserdata(L, sizeof(struct dict*));
 		*udbootenv = img->bootloader;
-		luaL_setfuncs(gL, l_swupdate_bootenv, 1);
-		lua_pop(gL, 1);
+		luaL_setfuncs(L, l_swupdate_bootenv, 1);
+		lua_pop(L, 1);
 	}

 	l_func_ref = *((int*)data);
 	/* get the callback function */
-	lua_rawgeti(gL, LUA_REGISTRYINDEX, l_func_ref );
-	image2table(gL, img);
+	lua_rawgeti(L, LUA_REGISTRYINDEX, l_func_ref );
+	image2table(L, img);

 	switch (scriptfn) {
 	case PREINSTALL:
-		lua_pushstring(gL, "preinst");
+		lua_pushstring(L, "preinst");
 		break;
 	case POSTINSTALL:
-		lua_pushstring(gL, "postinst");
+		lua_pushstring(L, "postinst");
 		break;
 	default:
-		lua_pushnil(gL);
+		lua_pushnil(L);
 		break;
 	}

-	if (LUA_OK != (res = lua_pcall(gL, 2, 1, 0))) {
+	if (LUA_OK != (res = lua_pcall(L, 2, 1, 0))) {
 		ERROR("Error %d while executing the Lua callback: %s",
-			  res, lua_tostring(gL, -1));
-		lua_pop(gL, 1);
+			  res, lua_tostring(L, -1));
+		lua_pop(L, 1);
 		return -1;
 	}

 	 /* retrieve result */
-	if (!lua_isnumber(gL, -1)) {
+	if (!lua_isnumber(L, -1)) {
 		ERROR("Lua Handler must return a number");
-		lua_pop(gL, 1);
+		lua_pop(L, 1);
 		return -1;
 	}

-	result = lua_tonumber(gL, -1);
-	lua_pop(gL, 1);
+	result = lua_tonumber(L, -1);
+	lua_pop(L, 1);
 	TRACE("[Lua handler] returned: %d",(int)result);

 	return (int) result;
@@ -1398,6 +1407,8 @@  static int l_other_handler_wrapper(struct img_type *img, void *data)
  */
 static int l_register_handler( lua_State *L ) {
 	int *l_func_ref = malloc(sizeof(int));
+	handler_type_t lifetime = GLOBAL_HANDLER;
+
 	if(!l_func_ref) {
 		ERROR("Lua handler: unable to allocate memory");
 		lua_pop(L, 2);
@@ -1423,16 +1434,35 @@  static int l_register_handler( lua_State *L ) {
 		}

 		const char *handler_desc = luaL_checkstring(L, 1);
+
+		/*
+		 * Check if the handler must be registered globally
+		 * or just during the update
+		 */
+		if (L != gL) {
+			lifetime = SESSION_HANDLER;
+		}
 		/* store the callback function in registry */
 		*l_func_ref = luaL_ref (L, LUA_REGISTRYINDEX);
 		/* cleanup stack */
 		lua_pop (L, 1);

-		register_handler(handler_desc,
+		switch (lifetime) {
+		case GLOBAL_HANDLER:
+			register_handler(handler_desc,
+				 (mask & SCRIPT_HANDLER) ?
+				 l_script_handler_wrapper :
+				 l_other_handler_wrapper,
+				 mask, l_func_ref);
+			break;
+		case SESSION_HANDLER:
+			register_session_handler(handler_desc,
 				 (mask & SCRIPT_HANDLER) ?
 				 l_script_handler_wrapper :
 				 l_other_handler_wrapper,
 				 mask, l_func_ref);
+			break;
+		}
 		return 0;
 	}
 }
@@ -1486,7 +1516,7 @@  call_handler_exit:
 	return 2;
 }

-int lua_handlers_init(void)
+int lua_handlers_init(lua_State *L)
 {
 	static const char location[] =
 #if defined(CONFIG_EMBEDDED_LUA_HANDLER)
@@ -1496,26 +1526,29 @@  int lua_handlers_init(void)
 #endif
 	int ret = -1;

-	gL = luaL_newstate();
-	if (gL) {
+	if (!L) {
+		gL = luaL_newstate();
+		L = gL;
+	}
+	if (L) {
 		/* prime gL as LUA_TYPE_HANDLER */
-		lua_pushlightuserdata(gL, (void*)LUA_TYPE_HANDLER);
-		lua_setglobal(gL, "SWUPDATE_LUA_TYPE");
+		lua_pushlightuserdata(L, (void*)LUA_TYPE_HANDLER);
+		lua_setglobal(L, "SWUPDATE_LUA_TYPE");
 		/* load standard libraries */
-		luaL_openlibs(gL);
-		luaL_requiref( gL, "swupdate", luaopen_swupdate, 1 );
-		lua_pop(gL, 1); /* remove unused copy left on stack */
+		luaL_openlibs(L);
+		luaL_requiref(L, "swupdate", luaopen_swupdate, 1 );
+		lua_pop(L, 1); /* remove unused copy left on stack */
 		/* try to load Lua handlers for the swupdate system */
 #if defined(CONFIG_EMBEDDED_LUA_HANDLER)
-		ret = (luaL_loadbuffer(gL, EMBEDDED_LUA_SRC_START, EMBEDDED_LUA_SRC_END-EMBEDDED_LUA_SRC_START, "LuaHandler") ||
-		       lua_pcall(gL, 0, LUA_MULTRET, 0));
+		ret = (luaL_loadbuffer(L, EMBEDDED_LUA_SRC_START, EMBEDDED_LUA_SRC_END-EMBEDDED_LUA_SRC_START, "LuaHandler") ||
+		       lua_pcall(L, 0, LUA_MULTRET, 0));
 #else
-		ret = luaL_dostring(gL, "require (\"swupdate_handlers\")");
+		ret = luaL_dostring(L, "require (\"swupdate_handlers\")");
 #endif
 		if (ret != 0) {
 			INFO("%s Lua handler(s) not found.", location);
-			lua_report_exception(gL);
-			lua_pop(gL, 1);
+			lua_report_exception(L);
+			lua_pop(L, 1);
 		} else {
 			INFO("%s Lua handler(s) found and loaded.", location);
 		}
@@ -1542,6 +1575,8 @@  lua_State *lua_init(struct dict *bootenv)
 	luaL_setfuncs(L, l_swupdate_bootenv, 1);
 	lua_pop(L, 1); /* remove unused copy left on stack */

+	lua_handlers_init(L);
+
 	return L;
 }

diff --git a/include/lua_util.h b/include/lua_util.h
index 11d4c61f..2c43c751 100644
--- a/include/lua_util.h
+++ b/include/lua_util.h
@@ -25,7 +25,7 @@  lua_State *lua_init(struct dict *bootenv);
 int lua_load_buffer(lua_State *L, const char *buf);
 int lua_parser_fn(lua_State *L, const char *fcn, struct img_type *img);
 int lua_handler_fn(lua_State *L, const char *fcn, const char *parms);
-int lua_handlers_init(void);
+int lua_handlers_init(lua_State *L);

 int lua_notify_trace(lua_State *L);
 int lua_notify_error(lua_State *L);
@@ -109,5 +109,5 @@  static inline int lua_parser_fn(lua_State __attribute__ ((__unused__)) *L,
 static inline int lua_handler_fn(lua_State __attribute__ ((__unused__)) *L,
 			 const char __attribute__ ((__unused__)) *fcn,
 			 const char __attribute__ ((__unused__)) *parms) { return -1; }
-static inline int lua_handlers_init(void) { return 0; }
+static inline int lua_handlers_init(lua_State *L) { return 0; }
 #endif