You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
openwrt/package/uci/patches/120-uci_trigger.patch

183 lines
3.9 KiB
Diff

--- /dev/null
+++ b/trigger/Makefile
@@ -0,0 +1,44 @@
+include ../Makefile.inc
+LUA_VERSION=5.1
+PREFIX_SEARCH=/usr /usr/local /opt/local
+LUA_PLUGINDIR=$(firstword \
+ $(foreach ldir,$(subst ;, ,$(shell lua -e 'print(package.cpath)')), \
+ $(if $(findstring lib/lua/,$(ldir)),$(patsubst %/?.so,%,$(ldir))) \
+ ) \
+)
+
+# find lua prefix
+LUA_PREFIX=$(firstword \
+ $(foreach prefix,$(PREFIX_SEARCH),\
+ $(if $(wildcard $(prefix)/include/lua.h),$(prefix)) \
+ ) \
+)
+
+libdir=$(prefix)/libs
+luadir=$(if $(LUA_PLUGINDIR),$(LUA_PLUGINDIR),$(libdir)/lua/$(LUA_VERSION))
+luainc=$(shell pkg-config --silence-errors --cflags lua$(LUA_VERSION))
+
+CPPFLAGS=-I.. $(if $(luainc),$(luainc), -I$(LUA_PREFIX)/include)
+LIBS=-L.. -luci $(shell pkg-config --silence-errors --libs lua$(LUA_VERSION))
+
+PLUGIN_LD=$(CC)
+ifeq ($(OS),Darwin)
+ PLUGIN_LDFLAGS=-bundle
+else
+ PLUGIN_LDFLAGS=-shared -Wl,-soname,$(SHLIB_FILE)
+endif
+
+all: uci_trigger.so
+
+uci_trigger.so: uci_trigger.o
+ $(PLUGIN_LD) $(PLUGIN_LDFLAGS) -o $@ $^ $(LIBS)
+
+%.o: %.c
+ $(CC) $(CPPFLAGS) $(CFLAGS) $(FPIC) -c -o $@ $<
+
+install:
+ mkdir -p $(DESTDIR)$(luadir)
+ $(INSTALL) -m0644 uci_trigger.so $(DESTDIR)$(luadir)/
+
+clean:
+ rm -f *.so *.o uci_trigger.so
--- /dev/null
+++ b/trigger/uci_trigger.c
@@ -0,0 +1,132 @@
+#include <sys/types.h>
+#include <sys/time.h>
+#include <stdbool.h>
+#include <string.h>
+#include <stdio.h>
+#include <lualib.h>
+#include <lauxlib.h>
+#include "uci.h"
+
+// #define DEBUG
+
+static int refcount = 0;
+static lua_State *gL = NULL;
+static bool prepared = false;
+
+struct trigger_set_op {
+ struct uci_package *p;
+ struct uci_delta *h;
+};
+
+static int trigger_set(lua_State *L)
+{
+ struct trigger_set_op *so =
+ (struct trigger_set_op *)lua_touserdata(L, 1);
+ struct uci_package *p = so->p;
+ struct uci_delta *h = so->h;
+ struct uci_context *ctx = p->ctx;
+
+ /* ignore non-standard savedirs/configdirs
+ * in order to not trigger events on uci state changes */
+ if (strcmp(ctx->savedir, UCI_SAVEDIR) ||
+ strcmp(ctx->confdir, UCI_CONFDIR))
+ return 0;
+
+ if (!prepared) {
+ lua_getglobal(L, "require");
+ lua_pushstring(L, "uci.trigger");
+ lua_call(L, 1, 0);
+
+ lua_getglobal(L, "uci");
+ lua_getfield(L, -1, "trigger");
+ lua_getfield(L, -1, "load_modules");
+ lua_call(L, 0, 0);
+ prepared = true;
+ } else {
+ lua_getglobal(L, "uci");
+ lua_getfield(L, -1, "trigger");
+ }
+
+ lua_getfield(L, -1, "set");
+ lua_createtable(L, 4, 0);
+
+ lua_pushstring(L, p->e.name);
+ lua_rawseti(L, -2, 1);
+ if (h->section) {
+ lua_pushstring(L, h->section);
+ lua_rawseti(L, -2, 2);
+ }
+ if (h->e.name) {
+ lua_pushstring(L, h->e.name);
+ lua_rawseti(L, -2, 3);
+ }
+ if (h->value) {
+ lua_pushstring(L, h->value);
+ lua_rawseti(L, -2, 4);
+ }
+ lua_call(L, 1, 0);
+ lua_pop(L, 2);
+ return 0;
+}
+
+#ifdef DEBUG
+
+static int report (lua_State *L, int status) {
+ if (status && !lua_isnil(L, -1)) {
+ const char *msg = lua_tostring(L, -1);
+ if (msg == NULL) msg = "(error object is not a string)";
+ fprintf(stderr, "ERROR: %s\n", msg);
+ lua_pop(L, 1);
+ }
+ return status;
+}
+
+#else
+
+static inline int report(lua_State *L, int status) {
+ return status;
+}
+
+#endif
+
+static void trigger_set_hook(const struct uci_hook_ops *ops, struct uci_package *p, struct uci_delta *h)
+{
+ struct trigger_set_op so;
+
+ so.p = p;
+ so.h = h;
+ report(gL, lua_cpcall(gL, &trigger_set, &so));
+}
+
+static struct uci_hook_ops hook = {
+ .set = trigger_set_hook,
+};
+
+static int trigger_attach(struct uci_context *ctx)
+{
+ if (!gL) {
+ gL = luaL_newstate();
+ if (!gL)
+ return -1;
+ luaL_openlibs(gL);
+
+ refcount++;
+ }
+ uci_add_hook(ctx, &hook);
+ return 0;
+}
+
+static void trigger_detach(struct uci_context *ctx)
+{
+ if (gL && (--refcount <= 0)) {
+ lua_close(gL);
+ gL = NULL;
+ refcount = 0;
+ prepared = false;
+ }
+}
+
+struct uci_plugin_ops uci_plugin = {
+ .attach = trigger_attach,
+ .detach = trigger_detach,
+};