183 lines
		
	
	
		
			3.9 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			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_history *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_history *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_history *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,
 | 
						|
+};
 |