add ucitrigger: a uci plugin, command line tool and lua interface for automatically...
[openwrt.git] / package / uci / patches / 120-uci_trigger.patch
diff --git a/package/uci/patches/120-uci_trigger.patch b/package/uci/patches/120-uci_trigger.patch
new file mode 100644 (file)
index 0000000..a1454a3
--- /dev/null
@@ -0,0 +1,182 @@
+--- /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,
++};
This page took 0.030263 seconds and 4 git commands to generate.