diff --git a/CMakeLists.txt b/CMakeLists.txt index aa0d3e0..64bb667 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -38,6 +38,20 @@ list (APPEND project_libraries ${libssl_LIBRARIES}) include_directories (${libssl_INCLUDE_DIRS}) link_directories (${libssl_LIBRARY_DIRS}) +# FIXME: other Lua versions may be acceptable, don't know yet +pkg_search_module (lua lua5.3 lua-5.3 lua>=5.3) +option (WITH_LUA "Enable experimental support for Lua plugins" ${lua_FOUND}) + +if (WITH_LUA) + if (NOT lua_FOUND) + message (FATAL_ERROR "Lua library not found") + endif (NOT lua_FOUND) + + list (APPEND project_libraries ${lua_LIBRARIES}) + include_directories (${lua_INCLUDE_DIRS}) + link_directories (${lua_LIBRARY_DIRS}) +endif (WITH_LUA) + # -lpthread is only there for debugging (gdb & errno) # -lrt is only for glibc < 2.17 # -liconv may or may not be a part of libc @@ -75,13 +89,9 @@ elseif (WANT_LIBEDIT) endif ((WANT_READLINE AND WANT_LIBEDIT) OR (NOT WANT_READLINE AND NOT WANT_LIBEDIT)) # Generate a configuration file -if (WANT_READLINE) - set (HAVE_READLINE 1) -endif (WANT_READLINE) - -if (WANT_LIBEDIT) - set (HAVE_EDITLINE 1) -endif (WANT_LIBEDIT) +set (HAVE_READLINE "${WANT_READLINE}") +set (HAVE_EDITLINE "${WANT_LIBEDIT}") +set (HAVE_LUA "${WITH_LUA}") include (GNUInstallDirs) set (plugin_dir ${CMAKE_INSTALL_LIBDIR}/${PROJECT_NAME}) diff --git a/config.h.in b/config.h.in index 63eca68..833f874 100644 --- a/config.h.in +++ b/config.h.in @@ -6,5 +6,6 @@ #cmakedefine HAVE_READLINE #cmakedefine HAVE_EDITLINE +#cmakedefine HAVE_LUA #endif // ! CONFIG_H diff --git a/degesch.c b/degesch.c index 1a2ae20..ac54ded 100644 --- a/degesch.c +++ b/degesch.c @@ -79,6 +79,12 @@ enum #include #endif // HAVE_EDITLINE +#ifdef HAVE_LUA +#include +#include +#include +#endif // HAVE_LUA + /// Some arbitrary limit for the history file #define HISTORY_LIMIT 10000 @@ -7129,6 +7135,95 @@ server_rename (struct app_context *ctx, struct server *s, const char *new_name) } } +// --- Lua --------------------------------------------------------------------- + +#ifdef HAVE_LUA + +struct lua_plugin +{ + struct plugin super; ///< The structure we're deriving + struct app_context *ctx; ///< Application context + lua_State *L; ///< Lua state +}; + +static void +lua_plugin_free (struct plugin *self_) +{ + struct lua_plugin *self = (struct lua_plugin *) self_; + lua_close (self->L); +} + +struct plugin_vtable lua_plugin_vtable = +{ + .free = lua_plugin_free, +}; + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +static void * +lua_plugin_alloc (void *ud, void *ptr, size_t o_size, size_t n_size) +{ + (void) ud; + (void) o_size; + + if (n_size) + return realloc (ptr, n_size); + + free (ptr); + return NULL; +} + +static int +lua_plugin_panic (lua_State *L) +{ + // XXX: we might be able to do something better + print_fatal ("Lua panicked: %s", lua_tostring (L, -1)); + lua_close (L); + exit (EXIT_FAILURE); + return 0; +} + +static luaL_Reg lua_plugin_library[] = +{ + { NULL, NULL }, +}; + +static struct plugin * +lua_plugin_load (struct app_context *ctx, const char *filename, + struct error **e) +{ + lua_State *L = lua_newstate (lua_plugin_alloc, NULL); + if (!L) + { + error_set (e, "Lua initialization failed"); + return NULL; + } + + lua_atpanic (L, lua_plugin_panic); + luaL_openlibs (L); + + luaL_newlib (L, lua_plugin_library); + lua_setglobal (L, PROGRAM_NAME); + + int ret; + if ((ret = luaL_loadfile (L, filename)) + || (ret = lua_pcall (L, 0, 0, 0))) + { + error_set (e, "%s: %s", "Lua", lua_tostring (L, -1)); + lua_close (L); + return NULL; + } + + struct lua_plugin *plugin = xcalloc (1, sizeof *plugin); + plugin->super.name = NULL; + plugin->super.vtable = &lua_plugin_vtable; + plugin->ctx = ctx; + plugin->L = L; + return &plugin->super; +} + +#endif // HAVE_LUA + // --- Plugins ----------------------------------------------------------------- typedef struct plugin *(*plugin_load_fn) @@ -7138,6 +7233,9 @@ typedef struct plugin *(*plugin_load_fn) // however this possibility is just a byproduct of abstraction static plugin_load_fn g_plugin_loaders[] = { +#ifdef HAVE_LUA + lua_plugin_load, +#endif // HAVE_LUA }; static struct plugin *