mirror of
				git://git.openwrt.org/openwrt/openwrt.git
				synced 2025-10-31 05:54:26 -04:00 
			
		
		
		
	
		
			
				
	
	
		
			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_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,
 | |
| +};
 |