8ea9667036
It mostly mimick the style of the existing code. With it and the ubox Lua bindings, you can now send ubus events through Lua or listen for events (you can register for multiple events at the same time). Signed-off-by: Jeff Remy <jeff.remy@gmail.com>
727 lines
15 KiB
C
727 lines
15 KiB
C
/*
|
|
* Copyright (C) 2012 Jo-Philipp Wich <jow@openwrt.org>
|
|
* Copyright (C) 2012 John Crispin <blogic@openwrt.org>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU Lesser General Public License version 2.1
|
|
* as published by the Free Software Foundation
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*/
|
|
|
|
#include <unistd.h>
|
|
#include <libubus.h>
|
|
#include <libubox/blobmsg.h>
|
|
#include <libubox/blobmsg_json.h>
|
|
#include <lauxlib.h>
|
|
#include <lua.h>
|
|
|
|
#define MODNAME "ubus"
|
|
#define METANAME MODNAME ".meta"
|
|
|
|
static lua_State *state;
|
|
|
|
struct ubus_lua_connection {
|
|
int timeout;
|
|
struct blob_buf buf;
|
|
struct ubus_context *ctx;
|
|
};
|
|
|
|
struct ubus_lua_object {
|
|
struct ubus_object o;
|
|
int r;
|
|
};
|
|
|
|
struct ubus_lua_event {
|
|
struct ubus_event_handler e;
|
|
int r;
|
|
};
|
|
|
|
static int
|
|
ubus_lua_parse_blob(lua_State *L, struct blob_attr *attr, bool table);
|
|
|
|
static int
|
|
ubus_lua_parse_blob_array(lua_State *L, struct blob_attr *attr, int len, bool table)
|
|
{
|
|
int rv;
|
|
int idx = 1;
|
|
int rem = len;
|
|
struct blob_attr *pos;
|
|
|
|
lua_newtable(L);
|
|
|
|
__blob_for_each_attr(pos, attr, rem)
|
|
{
|
|
rv = ubus_lua_parse_blob(L, pos, table);
|
|
|
|
if (rv > 1)
|
|
lua_rawset(L, -3);
|
|
else if (rv > 0)
|
|
lua_rawseti(L, -2, idx++);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
ubus_lua_parse_blob(lua_State *L, struct blob_attr *attr, bool table)
|
|
{
|
|
int len;
|
|
int off = 0;
|
|
void *data;
|
|
|
|
if (!blobmsg_check_attr(attr, false))
|
|
return 0;
|
|
|
|
if (table && blobmsg_name(attr)[0])
|
|
{
|
|
lua_pushstring(L, blobmsg_name(attr));
|
|
off++;
|
|
}
|
|
|
|
data = blobmsg_data(attr);
|
|
len = blobmsg_data_len(attr);
|
|
|
|
switch (blob_id(attr))
|
|
{
|
|
case BLOBMSG_TYPE_BOOL:
|
|
lua_pushboolean(L, *(uint8_t *)data);
|
|
break;
|
|
|
|
case BLOBMSG_TYPE_INT16:
|
|
lua_pushinteger(L, be16_to_cpu(*(uint16_t *)data));
|
|
break;
|
|
|
|
case BLOBMSG_TYPE_INT32:
|
|
lua_pushinteger(L, be32_to_cpu(*(uint32_t *)data));
|
|
break;
|
|
|
|
case BLOBMSG_TYPE_INT64:
|
|
lua_pushnumber(L, (double) be64_to_cpu(*(uint64_t *)data));
|
|
break;
|
|
|
|
case BLOBMSG_TYPE_STRING:
|
|
lua_pushstring(L, data);
|
|
break;
|
|
|
|
case BLOBMSG_TYPE_ARRAY:
|
|
ubus_lua_parse_blob_array(L, data, len, false);
|
|
break;
|
|
|
|
case BLOBMSG_TYPE_TABLE:
|
|
ubus_lua_parse_blob_array(L, data, len, true);
|
|
break;
|
|
|
|
default:
|
|
lua_pushnil(L);
|
|
break;
|
|
}
|
|
|
|
return off + 1;
|
|
}
|
|
|
|
|
|
static bool
|
|
ubus_lua_format_blob_is_array(lua_State *L)
|
|
{
|
|
lua_Integer prv = 0;
|
|
lua_Integer cur = 0;
|
|
|
|
/* Find out whether table is array-like */
|
|
for (lua_pushnil(L); lua_next(L, -2); lua_pop(L, 1))
|
|
{
|
|
#ifdef LUA_TINT
|
|
if (lua_type(L, -2) != LUA_TNUMBER && lua_type(L, -2) != LUA_TINT)
|
|
#else
|
|
if (lua_type(L, -2) != LUA_TNUMBER)
|
|
#endif
|
|
{
|
|
lua_pop(L, 2);
|
|
return false;
|
|
}
|
|
|
|
cur = lua_tointeger(L, -2);
|
|
|
|
if ((cur - 1) != prv)
|
|
{
|
|
lua_pop(L, 2);
|
|
return false;
|
|
}
|
|
|
|
prv = cur;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static int
|
|
ubus_lua_format_blob_array(lua_State *L, struct blob_buf *b, bool table);
|
|
|
|
static int
|
|
ubus_lua_format_blob(lua_State *L, struct blob_buf *b, bool table)
|
|
{
|
|
void *c;
|
|
bool rv = true;
|
|
const char *key = table ? lua_tostring(L, -2) : NULL;
|
|
|
|
switch (lua_type(L, -1))
|
|
{
|
|
case LUA_TBOOLEAN:
|
|
blobmsg_add_u8(b, key, (uint8_t)lua_toboolean(L, -1));
|
|
break;
|
|
|
|
#ifdef LUA_TINT
|
|
case LUA_TINT:
|
|
#endif
|
|
case LUA_TNUMBER:
|
|
blobmsg_add_u32(b, key, (uint32_t)lua_tointeger(L, -1));
|
|
break;
|
|
|
|
case LUA_TSTRING:
|
|
case LUA_TUSERDATA:
|
|
case LUA_TLIGHTUSERDATA:
|
|
blobmsg_add_string(b, key, lua_tostring(L, -1));
|
|
break;
|
|
|
|
case LUA_TTABLE:
|
|
if (ubus_lua_format_blob_is_array(L))
|
|
{
|
|
c = blobmsg_open_array(b, key);
|
|
rv = ubus_lua_format_blob_array(L, b, false);
|
|
blobmsg_close_array(b, c);
|
|
}
|
|
else
|
|
{
|
|
c = blobmsg_open_table(b, key);
|
|
rv = ubus_lua_format_blob_array(L, b, true);
|
|
blobmsg_close_table(b, c);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
rv = false;
|
|
break;
|
|
}
|
|
|
|
return rv;
|
|
}
|
|
|
|
static int
|
|
ubus_lua_format_blob_array(lua_State *L, struct blob_buf *b, bool table)
|
|
{
|
|
for (lua_pushnil(L); lua_next(L, -2); lua_pop(L, 1))
|
|
{
|
|
if (!ubus_lua_format_blob(L, b, table))
|
|
{
|
|
lua_pop(L, 1);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
static int
|
|
ubus_lua_connect(lua_State *L)
|
|
{
|
|
struct ubus_lua_connection *c;
|
|
const char *sockpath = luaL_optstring(L, 1, NULL);
|
|
int timeout = luaL_optint(L, 2, 30);
|
|
|
|
if ((c = lua_newuserdata(L, sizeof(*c))) != NULL &&
|
|
(c->ctx = ubus_connect(sockpath)) != NULL)
|
|
{
|
|
ubus_add_uloop(c->ctx);
|
|
c->timeout = timeout;
|
|
memset(&c->buf, 0, sizeof(c->buf));
|
|
luaL_getmetatable(L, METANAME);
|
|
lua_setmetatable(L, -2);
|
|
return 1;
|
|
}
|
|
|
|
/* NB: no errors from ubus_connect() yet */
|
|
lua_pushnil(L);
|
|
lua_pushinteger(L, UBUS_STATUS_UNKNOWN_ERROR);
|
|
return 2;
|
|
}
|
|
|
|
|
|
static void
|
|
ubus_lua_objects_cb(struct ubus_context *c, struct ubus_object_data *o, void *p)
|
|
{
|
|
lua_State *L = (lua_State *)p;
|
|
|
|
lua_pushstring(L, o->path);
|
|
lua_rawseti(L, -2, lua_objlen(L, -2) + 1);
|
|
}
|
|
|
|
static int
|
|
ubus_lua_objects(lua_State *L)
|
|
{
|
|
int rv;
|
|
struct ubus_lua_connection *c = luaL_checkudata(L, 1, METANAME);
|
|
|
|
lua_newtable(L);
|
|
rv = ubus_lookup(c->ctx, NULL, ubus_lua_objects_cb, L);
|
|
|
|
if (rv != UBUS_STATUS_OK)
|
|
{
|
|
lua_pop(L, 1);
|
|
lua_pushnil(L);
|
|
lua_pushinteger(L, rv);
|
|
return 2;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
ubus_method_handler(struct ubus_context *ctx, struct ubus_object *obj,
|
|
struct ubus_request_data *req, const char *method,
|
|
struct blob_attr *msg)
|
|
{
|
|
struct ubus_lua_object *o = container_of(obj, struct ubus_lua_object, o);
|
|
|
|
lua_getglobal(state, "__ubus_cb");
|
|
lua_rawgeti(state, -1, o->r);
|
|
lua_getfield(state, -1, method);
|
|
|
|
if (lua_isfunction(state, -1)) {
|
|
lua_pushlightuserdata(state, req);
|
|
if (!msg)
|
|
lua_pushnil(state);
|
|
else
|
|
ubus_lua_parse_blob_array(state, blob_data(msg), blob_len(msg), true);
|
|
lua_call(state, 2, 0);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int lua_gettablelen(lua_State *L, int index)
|
|
{
|
|
int cnt = 0;
|
|
|
|
lua_pushnil(L);
|
|
index -= 1;
|
|
while (lua_next(L, index) != 0) {
|
|
cnt++;
|
|
lua_pop(L, 1);
|
|
}
|
|
|
|
return cnt;
|
|
}
|
|
|
|
static int ubus_lua_reply(lua_State *L)
|
|
{
|
|
struct ubus_lua_connection *c = luaL_checkudata(L, 1, METANAME);
|
|
struct ubus_request_data *req;
|
|
|
|
luaL_checktype(L, 3, LUA_TTABLE);
|
|
blob_buf_init(&c->buf, 0);
|
|
|
|
if (!ubus_lua_format_blob_array(L, &c->buf, true))
|
|
{
|
|
lua_pushnil(L);
|
|
lua_pushinteger(L, UBUS_STATUS_INVALID_ARGUMENT);
|
|
return 2;
|
|
}
|
|
|
|
req = lua_touserdata(L, 2);
|
|
ubus_send_reply(c->ctx, req, c->buf.head);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int ubus_lua_load_methods(lua_State *L, struct ubus_method *m)
|
|
{
|
|
struct blobmsg_policy *p;
|
|
int plen;
|
|
int pidx = 0;
|
|
|
|
/* get the function pointer */
|
|
lua_pushinteger(L, 1);
|
|
lua_gettable(L, -2);
|
|
|
|
/* get the policy table */
|
|
lua_pushinteger(L, 2);
|
|
lua_gettable(L, -3);
|
|
plen = lua_gettablelen(L, -1);
|
|
|
|
/* check if the method table is valid */
|
|
if ((lua_type(L, -2) != LUA_TFUNCTION) ||
|
|
(lua_type(L, -1) != LUA_TTABLE) ||
|
|
lua_objlen(L, -1) || !plen) {
|
|
lua_pop(L, 2);
|
|
return 1;
|
|
}
|
|
|
|
/* store function pointer */
|
|
lua_pushvalue(L, -2);
|
|
lua_setfield(L, -6, lua_tostring(L, -5));
|
|
|
|
/* setup the policy pointers */
|
|
p = malloc(sizeof(struct blobmsg_policy) * plen);
|
|
memset(p, 0, sizeof(struct blobmsg_policy) * plen);
|
|
m->policy = p;
|
|
lua_pushnil(L);
|
|
while (lua_next(L, -2) != 0) {
|
|
int val = lua_tointeger(L, -1);
|
|
|
|
/* check if the policy is valid */
|
|
if ((lua_type(L, -2) != LUA_TSTRING) ||
|
|
(lua_type(L, -1) != LUA_TNUMBER) ||
|
|
(val < 0) ||
|
|
(val > BLOBMSG_TYPE_LAST)) {
|
|
lua_pop(L, 1);
|
|
continue;
|
|
}
|
|
p[pidx].name = lua_tostring(L, -2);
|
|
p[pidx].type = val;
|
|
lua_pop(L, 1);
|
|
pidx++;
|
|
}
|
|
|
|
m->n_policy = pidx;
|
|
m->name = lua_tostring(L, -4);
|
|
m->handler = ubus_method_handler;
|
|
lua_pop(L, 2);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static struct ubus_object* ubus_lua_load_object(lua_State *L)
|
|
{
|
|
struct ubus_lua_object *obj = NULL;
|
|
int mlen = lua_gettablelen(L, -1);
|
|
struct ubus_method *m;
|
|
int midx = 0;
|
|
|
|
/* setup object pointers */
|
|
obj = malloc(sizeof(struct ubus_lua_object));
|
|
memset(obj, 0, sizeof(struct ubus_lua_object));
|
|
obj->o.name = lua_tostring(L, -2);
|
|
|
|
/* setup method pointers */
|
|
m = malloc(sizeof(struct ubus_method) * mlen);
|
|
memset(m, 0, sizeof(struct ubus_method) * mlen);
|
|
obj->o.methods = m;
|
|
|
|
/* setup type pointers */
|
|
obj->o.type = malloc(sizeof(struct ubus_object_type));
|
|
memset(obj->o.type, 0, sizeof(struct ubus_object_type));
|
|
obj->o.type->name = lua_tostring(L, -2);
|
|
obj->o.type->id = 0;
|
|
obj->o.type->methods = obj->o.methods;
|
|
|
|
/* create the he callback lookup table */
|
|
lua_createtable(L, 1, 0);
|
|
lua_getglobal(L, "__ubus_cb");
|
|
lua_pushvalue(L, -2);
|
|
obj->r = luaL_ref(L, -2);
|
|
lua_pop(L, 1);
|
|
|
|
/* scan each method */
|
|
lua_pushnil(L);
|
|
while (lua_next(L, -3) != 0) {
|
|
/* check if it looks like a method */
|
|
if ((lua_type(L, -2) != LUA_TSTRING) ||
|
|
(lua_type(L, -1) != LUA_TTABLE) ||
|
|
!lua_objlen(L, -1)) {
|
|
lua_pop(L, 1);
|
|
continue;
|
|
}
|
|
|
|
if (!ubus_lua_load_methods(L, &m[midx]))
|
|
midx++;
|
|
lua_pop(L, 1);
|
|
}
|
|
|
|
obj->o.type->n_methods = obj->o.n_methods = midx;
|
|
|
|
/* pop the callback table */
|
|
lua_pop(L, 1);
|
|
|
|
return &obj->o;
|
|
}
|
|
|
|
static int ubus_lua_add(lua_State *L)
|
|
{
|
|
struct ubus_lua_connection *c = luaL_checkudata(L, 1, METANAME);
|
|
|
|
/* verify top level object */
|
|
if (lua_istable(L, 1)) {
|
|
lua_pushstring(L, "you need to pass a table");
|
|
lua_error(L);
|
|
return 0;
|
|
}
|
|
|
|
/* scan each object */
|
|
lua_pushnil(L);
|
|
while (lua_next(L, -2) != 0) {
|
|
struct ubus_object *obj = NULL;
|
|
|
|
/* check if the object has a table of methods */
|
|
if ((lua_type(L, -2) == LUA_TSTRING) && (lua_type(L, -1) == LUA_TTABLE)) {
|
|
obj = ubus_lua_load_object(L);
|
|
|
|
if (obj)
|
|
ubus_add_object(c->ctx, obj);
|
|
}
|
|
lua_pop(L, 1);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void
|
|
ubus_lua_signatures_cb(struct ubus_context *c, struct ubus_object_data *o, void *p)
|
|
{
|
|
lua_State *L = (lua_State *)p;
|
|
|
|
if (!o->signature)
|
|
return;
|
|
|
|
ubus_lua_parse_blob_array(L, blob_data(o->signature), blob_len(o->signature), true);
|
|
}
|
|
|
|
static int
|
|
ubus_lua_signatures(lua_State *L)
|
|
{
|
|
int rv;
|
|
struct ubus_lua_connection *c = luaL_checkudata(L, 1, METANAME);
|
|
const char *path = luaL_checkstring(L, 2);
|
|
|
|
rv = ubus_lookup(c->ctx, path, ubus_lua_signatures_cb, L);
|
|
|
|
if (rv != UBUS_STATUS_OK)
|
|
{
|
|
lua_pop(L, 1);
|
|
lua_pushnil(L);
|
|
lua_pushinteger(L, rv);
|
|
return 2;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
static void
|
|
ubus_lua_call_cb(struct ubus_request *req, int type, struct blob_attr *msg)
|
|
{
|
|
lua_State *L = (lua_State *)req->priv;
|
|
|
|
if (!msg)
|
|
lua_pushnil(L);
|
|
|
|
ubus_lua_parse_blob_array(L, blob_data(msg), blob_len(msg), true);
|
|
}
|
|
|
|
static int
|
|
ubus_lua_call(lua_State *L)
|
|
{
|
|
int rv, top;
|
|
uint32_t id;
|
|
struct ubus_lua_connection *c = luaL_checkudata(L, 1, METANAME);
|
|
const char *path = luaL_checkstring(L, 2);
|
|
const char *func = luaL_checkstring(L, 3);
|
|
|
|
luaL_checktype(L, 4, LUA_TTABLE);
|
|
blob_buf_init(&c->buf, 0);
|
|
|
|
if (!ubus_lua_format_blob_array(L, &c->buf, true))
|
|
{
|
|
lua_pushnil(L);
|
|
lua_pushinteger(L, UBUS_STATUS_INVALID_ARGUMENT);
|
|
return 2;
|
|
}
|
|
|
|
rv = ubus_lookup_id(c->ctx, path, &id);
|
|
|
|
if (rv)
|
|
{
|
|
lua_pushnil(L);
|
|
lua_pushinteger(L, rv);
|
|
return 2;
|
|
}
|
|
|
|
top = lua_gettop(L);
|
|
rv = ubus_invoke(c->ctx, id, func, c->buf.head, ubus_lua_call_cb, L, c->timeout * 1000);
|
|
|
|
if (rv != UBUS_STATUS_OK)
|
|
{
|
|
lua_pop(L, 1);
|
|
lua_pushnil(L);
|
|
lua_pushinteger(L, rv);
|
|
return 2;
|
|
}
|
|
|
|
return lua_gettop(L) - top;
|
|
}
|
|
|
|
static void
|
|
ubus_event_handler(struct ubus_context *ctx, struct ubus_event_handler *ev,
|
|
const char *type, struct blob_attr *msg)
|
|
{
|
|
struct ubus_lua_event *listener = container_of(ev, struct ubus_lua_event, e);
|
|
|
|
lua_getglobal(state, "__ubus_cb_event");
|
|
lua_rawgeti(state, -1, listener->r);
|
|
|
|
if (lua_isfunction(state, -1)) {
|
|
ubus_lua_parse_blob_array(state, blob_data(msg), blob_len(msg), true);
|
|
lua_call(state, 1, 0);
|
|
}
|
|
}
|
|
|
|
static struct ubus_event_handler*
|
|
ubus_lua_load_event(lua_State *L)
|
|
{
|
|
struct ubus_lua_event* event = NULL;
|
|
|
|
event = malloc(sizeof(struct ubus_lua_event));
|
|
memset(event, 0, sizeof(struct ubus_lua_event));
|
|
event->e.cb = ubus_event_handler;
|
|
|
|
/* update the he callback lookup table */
|
|
lua_getglobal(L, "__ubus_cb_event");
|
|
lua_pushvalue(L, -2);
|
|
event->r = luaL_ref(L, -2);
|
|
lua_setfield(L, -1, lua_tostring(L, -3));
|
|
|
|
return &event->e;
|
|
}
|
|
|
|
static int
|
|
ubus_lua_listen(lua_State *L) {
|
|
struct ubus_lua_connection *c = luaL_checkudata(L, 1, METANAME);
|
|
|
|
/* verify top level object */
|
|
luaL_checktype(L, 2, LUA_TTABLE);
|
|
|
|
/* scan each object */
|
|
lua_pushnil(L);
|
|
while (lua_next(L, -2) != 0) {
|
|
struct ubus_event_handler *listener;
|
|
|
|
/* check if the key is a string and the value is a method */
|
|
if ((lua_type(L, -2) == LUA_TSTRING) && (lua_type(L, -1) == LUA_TFUNCTION)) {
|
|
listener = ubus_lua_load_event(L);
|
|
if(listener != NULL) {
|
|
ubus_register_event_handler(c->ctx, listener, lua_tostring(L, -2));
|
|
}
|
|
}
|
|
lua_pop(L, 1);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
ubus_lua_send(lua_State *L)
|
|
{
|
|
struct ubus_lua_connection *c = luaL_checkudata(L, 1, METANAME);
|
|
const char *event = luaL_checkstring(L, 2);
|
|
|
|
if (*event == 0)
|
|
return luaL_argerror(L, 2, "no event name");
|
|
|
|
// Event content convert to ubus form
|
|
luaL_checktype(L, 3, LUA_TTABLE);
|
|
blob_buf_init(&c->buf, 0);
|
|
|
|
if (!ubus_lua_format_blob_array(L, &c->buf, true)) {
|
|
lua_pushnil(L);
|
|
lua_pushinteger(L, UBUS_STATUS_INVALID_ARGUMENT);
|
|
return 2;
|
|
}
|
|
|
|
// Send the event
|
|
ubus_send_event(c->ctx, event, c->buf.head);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
ubus_lua__gc(lua_State *L)
|
|
{
|
|
struct ubus_lua_connection *c = luaL_checkudata(L, 1, METANAME);
|
|
|
|
if (c->ctx != NULL)
|
|
{
|
|
ubus_free(c->ctx);
|
|
memset(c, 0, sizeof(*c));
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static const luaL_Reg ubus[] = {
|
|
{ "connect", ubus_lua_connect },
|
|
{ "objects", ubus_lua_objects },
|
|
{ "add", ubus_lua_add },
|
|
{ "reply", ubus_lua_reply },
|
|
{ "signatures", ubus_lua_signatures },
|
|
{ "call", ubus_lua_call },
|
|
{ "close", ubus_lua__gc },
|
|
{ "listen", ubus_lua_listen },
|
|
{ "send", ubus_lua_send },
|
|
{ "__gc", ubus_lua__gc },
|
|
{ NULL, NULL },
|
|
};
|
|
|
|
/* avoid missing prototype warning */
|
|
int luaopen_ubus(lua_State *L);
|
|
|
|
int
|
|
luaopen_ubus(lua_State *L)
|
|
{
|
|
/* create metatable */
|
|
luaL_newmetatable(L, METANAME);
|
|
|
|
/* metatable.__index = metatable */
|
|
lua_pushvalue(L, -1);
|
|
lua_setfield(L, -2, "__index");
|
|
|
|
/* fill metatable */
|
|
luaL_register(L, NULL, ubus);
|
|
lua_pop(L, 1);
|
|
|
|
/* create module */
|
|
luaL_register(L, MODNAME, ubus);
|
|
|
|
/* set some enum defines */
|
|
lua_pushinteger(L, BLOBMSG_TYPE_ARRAY);
|
|
lua_setfield(L, -2, "ARRAY");
|
|
lua_pushinteger(L, BLOBMSG_TYPE_TABLE);
|
|
lua_setfield(L, -2, "TABLE");
|
|
lua_pushinteger(L, BLOBMSG_TYPE_STRING);
|
|
lua_setfield(L, -2, "STRING");
|
|
lua_pushinteger(L, BLOBMSG_TYPE_INT64);
|
|
lua_setfield(L, -2, "INT64");
|
|
lua_pushinteger(L, BLOBMSG_TYPE_INT32);
|
|
lua_setfield(L, -2, "INT32");
|
|
lua_pushinteger(L, BLOBMSG_TYPE_INT16);
|
|
lua_setfield(L, -2, "INT16");
|
|
lua_pushinteger(L, BLOBMSG_TYPE_INT8);
|
|
lua_setfield(L, -2, "INT8");
|
|
lua_pushinteger(L, BLOBMSG_TYPE_BOOL);
|
|
lua_setfield(L, -2, "BOOLEAN");
|
|
|
|
/* used in our callbacks */
|
|
state = L;
|
|
|
|
/* create the callback table */
|
|
lua_createtable(L, 1, 0);
|
|
lua_setglobal(L, "__ubus_cb");
|
|
|
|
/* create the event table */
|
|
lua_createtable(L, 1, 0);
|
|
lua_setglobal(L, "__ubus_cb_event");
|
|
|
|
return 0;
|
|
}
|