Commit 997717cf authored by Renato Figueiro Maia's avatar Renato Figueiro Maia

[OPENBUS-2739] Permitir modo interativo do 'busconsole' e 'busadmin'

[OPENBUS-2740] Tornar o 'busadmin' um 'busconsole' estendido com funções Lua de governaça
- Falta implementar suporte multithread preemptivo para Lua no Windows (sdk/lua/trunk/src/threadlib.c) 

git-svn-id: https://subversion.tecgraf.puc-rio.br/engdist/openbus/sdk/lua/trunk@161102 ae0415b3-e90b-0410-900d-d0be9363c56b
parent e93771a4
return function(...)
local _G = require "_G"
local _VERSION = _G._VERSION
local print = _G.print
local select = _G.select
local array = require "table"
local concat = array.concat
local io = require "io"
local stderr = io.stderr
local os = require "os"
local exit = os.exit
local Arguments = require "loop.compiler.Arguments"
local utils = require "openbus.console.utils"
local processargs = utils.processargs
local executables = {}
local args = Arguments{
i = false,
v = false,
E = false,
}
function args:e(_, value)
executables[#executables+1] = {kind="code", value=value}
end
function args:l(_, value)
executables[#executables+1] = {kind="module", value=value}
end
local finish = select("#", ...)
local start, errmsg = args(...)
if start == nil then
stderr:write(errmsg, "\n")
stderr:write([=[
usage: ]=]..OPENBUS_PROGNAME..[=[ [options] [script [args]].
Available options are:
-e stat execute string 'stat'
-i enter interactive mode after executing 'script'
-l name require library 'name'
-v show version information
-E ignore environment variables
]=])
return 1
end
if finish == 0 then
args.i = true
args.v = true
end
if args.v then
local idl = require "openbus.core.idl"
local version = concat({
idl.const.MajorVersion,
idl.const.MinorVersion,
0,
OPENBUS_CODEREV,
}, ".")
print("OpenBus "..version.." for ".._VERSION..
" Copyright (C) 2006-2015 Tecgraf, PUC-Rio")
end
OPENBUS_EXITCODE = processargs(_ENV, args.E, args.i, executables, select(start, ...))
end
return function (...)
local _G = require "_G"
local assert = _G.assert
local ipairs = _G.ipairs
local select = _G.select
local tonumber = _G.tonumber
local tostring = _G.tostring
local package = require "package"
local preload = package.preload
local array = require "table"
local unpack = array.unpack
local io = require "io"
local Wrapper = require "loop.object.Wrapper"
local cothread = require "cothread"
cothread.plugin(require "cothread.plugin.socket")
local socket = require "cothread.socket"
local newsocket = socket.tcp
local Mutex = require "cothread.Mutex"
local thread = require "openbus.util.thread"
local spawn = thread.spawn
local ValidFormats = {
["*n"] = true,
["*a"] = true,
["*l"] = true,
["*L"] = true,
["*?"] = true,
}
local sock = assert(newsocket())
assert(sock:bind("127.0.0.1", 0))
local _, port = assert(sock:getsockname())
assert(sock:listen())
local extra = ""
if preload.lpw ~= nil then
extra = [[
["*?"] = require("lpw").getpass,
]]
end
spawn([[
local io = require "io"
local readline = io.read
local cothread = require "cothread"
cothread.plugin(require "cothread.plugin.socket")
local socket = require "cothread.socket"
local newsocket = socket.tcp
local Message = "%d\n%s"
local handlers = {
]]..extra..[[
}
local sock = newsocket()
assert(sock:connect("localhost", ]]..port..[[))
while true do
local format = sock:receive()
if format ~= nil then
local handler = handlers[format]
if handler ~= nil then
result = handler()
else
result = readline(format)
end
assert(sock:send(#result.."\n"..result))
else
assert(sock:close())
break
end
end
]])
local conn = assert(sock:accept())
assert(sock:close())
local stdin = io.stdin
local mutex = Mutex()
local RemoteStdIn = Wrapper{ __object = stdin }
function RemoteStdIn:read(...)
local results = {}
for index = 1, select("#", ...) do
local format = select(index, ...)
assert(ValidFormats[format] or tonumber(format), "illegal format")
results[index] = format
end
if #results == 0 then results[1] = "*l" end
if mutex:try() then
for index, format in ipairs(results) do
conn:send(tostring(format).."\n")
local size = tonumber(conn:receive())
results[index] = size == 0 and "" or conn:receive(size)
end
mutex:free()
return unpack(results)
end
return nil, "denied by other thread"
end
local inactive = false
if stdin ~= nil then
io.stdin = RemoteStdIn
end
local stdread = io.read
if stdread ~= nil then
function io.read(...)
if not inactive then
return RemoteStdIn:read(...)
end
return stdread(...)
end
end
local stdinput = io.input
if stdinput ~= nil then
function io.input(file)
local wasinactive = inactive
inactive = file ~= RemoteStdIn
if wasinactive then
if inactive then
return stdinput(file)
else
return stdinput(stdin)
end
end
return RemoteStdIn
end
end
end
local _G = require "_G"
local _VERSION = _G._VERSION
local assert = _G.assert
local ipairs = _G.ipairs
local load = _G.load
local loadfile = _G.loadfile
local pcall = _G.pcall
local select = _G.select
local tostring = _G.tostring
local xpcall = _G.xpcall
local array = require "table"
local concat = array.concat
local string = require "string"
local replace = string.gsub
local allmatches = string.gmatch
local match = string.match
local substring = string.sub
local io = require "io"
local readline = io.read
local stderr = io.stderr
local stdout = io.stdout
local os = require "os"
local getenv = os.getenv
local debug = require "debug"
local getregistry = debug.getregistry
local traceback = debug.traceback
local function results(success, ...)
if success then
local message = {}
for i = 1, select("#", ...) do
message[#message+1] = tostring(select(i, ...))
end
return true, concat(message, "\t")
end
return nil, tostring(...)
end
local function protectedcall(code, ...)
local ok, result = xpcall(code, traceback, ...)
if not ok then return result end
return nil, result
end
local loaders = {
code = function (code, env)
return load(code, "=(command line)", "t", env)
end,
module = function (modname, env)
local result = env.require or require
return result, modname
end,
}
local function openconsole(env)
local lines = {}
while true do
if #lines == 0 then
io.write(_G._PROMPT or "> ")
else
io.write(_G._PROMPT2 or ">> ")
end
io.flush()
local result, message = readline()
if result ~= nil then
if #lines == 0 then result = replace(result, "^=", "return ") end
lines[#lines+1] = result
result, message = load(concat(lines, "\n"), "=stdin", "t", env)
if result ~= nil then
lines = {}
result, message = results(pcall(result))
elseif match(message, "<eof>$") then
result, message = true, nil
else
lines = {}
end
else
break
end
if result == nil or (message and #message > 0) then
local output = result and stdout or stderr
output:write(message, "\n")
output:flush()
end
end
end
local module = {}
function module.processargs(env, ignorevars, interactive, executables, script, ...)
local errmsg
if not ignorevars then
local name = replace(_VERSION, "Lua (%d+)%.(%d+)", "LUA_INIT_%1_%2")
local init = getenv(name)
if init == nil then
name = "LUA_INIT"
init = getenv(name)
end
if init ~= nil then
if match(init, "^@") then
init, errmsg = loadfile(substring(init, 2), "t")
else
init, errmsg = load(init, name, "t")
end
if init ~= nil then
errmsg = protectedcall(init)
end
end
else
getregistry().LUA_NOENV = true -- it is too late for this to work!
end
local exitvalue
if errmsg == nil then
for _, executable in ipairs(executables) do
local code, result = loaders[executable.kind](executable.value, env)
if code == nil then
errmsg = result
break
else
errmsg, result = protectedcall(code, result)
if errmsg ~= nil then break end
if executable.kind == "module" then
local modname = executable.value
local place = env
for name in allmatches(modname, "([^.]+)%.") do
local table = place[name]
if table == nil then
table = {}
place[name] = table
end
place = table
end
place[match(modname, "([^.]+)$")] = result
end
end
end
if errmsg == nil and script ~= nil then
local code, result = loadfile(script, "t")
if code == nil then
errmsg = result
else
errmsg, exitvalue = protectedcall(code, ...)
end
end
end
if errmsg ~= nil then
stderr:write(errmsg, "\n")
return 1
elseif interactive then
openconsole(env)
elseif exitvalue ~= nil then
return exitvalue
end
end
return module
......@@ -37,13 +37,23 @@ local function makeaux(def, types, consts, excepts)
local repID = def.repID
types[name] = repID
local logmsg = name.." "
excepts[name] = function(fields)
local function new(fields)
if fields == nil then fields = {} end
log:exception(logmsg:tag(fields))
fields[1] = message
fields._repid = repID
error(Exception(fields))
return Exception(fields)
end
local function throw(fields)
local except = new(fields)
log:exception(logmsg:tag(except))
error(except)
end
local function isa(value)
return type(value) == "table" and value._repid == repID
end
excepts[name] = throw
excepts["new_"..name] = new
excepts["is_"..name] = isa
elseif def._type == "const" then
consts[name] = def.val
elseif name ~= nil then
......
......@@ -22,7 +22,7 @@ local string = require "string"
local module = {}
function module.create()
function module.create(...)
local preloaded = {}
local packcfg = {
preload = preloaded,
......@@ -155,23 +155,31 @@ function module.create()
env[name] = module
end
local forbiden = {...}
function env.require(name)
local module = allowed[name]
if module == nil then
local isforbiden
for _, pattern in ipairs(forbiden) do
if match(name, pattern) then
isforbiden = true
end
end
if isforbiden then
error("no permission to load module '"..name.."'")
end
local loader = preloaded[name]
if loader ~= nil then
module = loader(name)
if module == nil then
module = true
end
elseif preload[name] == nil and loaded[name] == nil then
else
local path, cpath = package.path, package.cpath
package.path, package.cpath = packcfg.path, packcfg.cpath
local ok, result = xpcall(require, traceback, name)
package.path, package.cpath = path, cpath
if not ok then error(result) end
else
error("no permission to load module '"..name.."'")
end
allowed[name] = module
end
......
PROJNAME= busconsole
APPNAME= $(PROJNAME)
CODEREV?= r$(shell svnversion -n $(PROJDIR))
ifdef USE_LUA52
SRC= console.c
else
SRC= consoleLua51.c
endif
SRC= \
launcher.c \
consolelibs.c \
$(PRELOAD_DIR)/luaconsole.c
LUADIR= ../lua
LUASRC= \
$(LUADIR)/openbus/console.lua
include ${LOOP_HOME}/openbus/base.mak
DEFINES= \
OPENBUS_PROGNAME=\"$(APPNAME)\" \
OPENBUS_CODEREV=\"$(CODEREV)\"
LIBS:= \
luastruct \
......@@ -23,7 +33,8 @@ LIBS:= \
luascs \
luaopenbus
INCLUDES+= . $(SRCLUADIR) \
INCLUDES+= . \
$(SRCLUADIR) \
$(LUASTRUCT_HOME)/src \
$(LUASOCKET_HOME)/include \
$(LUATUPLE_HOME)/obj/$(TEC_UNAME) \
......@@ -108,3 +119,13 @@ ifneq ($(findstring $(TEC_SYSNAME), Win32 Win64), )
else
LIBS+= dl
endif
$(PRELOAD_DIR)/luaconsole.c $(PRELOAD_DIR)/luaconsole.h: $(LUAPRELOADER) $(LUASRC)
$(LOOPBIN) $(LUAPRELOADER) -l "$(LUADIR)/?.lua" \
-d $(PRELOAD_DIR) \
-h luaconsole.h \
-o luaconsole.c \
$(LUASRC)
luaconsole.c: $(PRELOAD_DIR)/luaconsole.h
consolelibs.c: $(PRELOAD_DIR)/luaconsole.h
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
#include "extralibraries.h"
#include "lua.h"
#include "lauxlib.h"
#include "luaconsole.h"
#if !defined(LUA_VERSION_NUM) || LUA_VERSION_NUM == 501
#include "compat-5.2.h"
#endif
const char const* OPENBUS_MAIN = "openbus.console";
void luapreload_extralibraries(lua_State *L)
{
luapreload_luaconsole(L);
}
#ifndef EXTRALIBRARIES_H
#define EXTRALIBRARIES_H
#include "lua.h"
extern const char const* OPENBUS_MAIN;
void luapreload_extralibraries(lua_State*);
#endif
/*
** $Id: lua.c,v 1.206 2012/09/29 20:07:06 roberto Exp $
** Lua stand-alone interpreter
** See Copyright Notice in lua.h
*/
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
#if !defined(LUA_VERSION_NUM) || LUA_VERSION_NUM == 501
#include <compat-5.2.h>
#include <luacompat52.h>
#endif
#include "openbuslua.h"
#include "extralibraries.h"
static int l_setlogpath (lua_State *L) {
const char *path = luaL_checkstring(L, 1);
if (openbuslua_setlogpath(path) != LUA_OK) {
luaL_error(L, "unable to set log path");
}
return 0;
}
static int pmain (lua_State *L) {
char **argv = (char **)lua_touserdata(L, 2);
int debugmode = argv[0] && argv[1] && strcmp(argv[1], "DEBUG") == 0;
luapreload_extralibraries(L);
int status = openbuslua_init(L, 1, debugmode);
if (status == LUA_OK) {
lua_pushliteral(L, OPENBUS_PROGNAME);
lua_setglobal(L, "OPENBUS_PROGNAME");
#ifdef OPENBUS_CODEREV
lua_pushliteral(L, OPENBUS_CODEREV);
lua_setglobal(L, "OPENBUS_CODEREV");
#endif
lua_pushstring(L, OPENBUS_MAIN);
lua_setglobal(L, "OPENBUS_MAIN");
lua_pushstring(L, argv[0]);
lua_setglobal(L, "OPENBUS_PROGPATH");
lua_pushcfunction(L, l_setlogpath);
lua_setglobal(L, "OPENBUS_SETLOGPATH");
lua_getglobal(L, "require");
lua_pushstring(L, OPENBUS_MAIN);
status = lua_pcall(L, 1, 1, 0);
if (status == LUA_OK) {
if (debugmode) ++argv;
int narg = openbuslua_pushargs(L, argv); /* collect arguments */
status = openbuslua_call(L, narg+1, 1);
if ( (status == LUA_OK) && lua_isnumber(L, -1) ) return 1;
}
}
openbuslua_report(L, status);
lua_pushinteger(L, EXIT_FAILURE);
return 1;
}
int main (int argc, char **argv) {
int status, result = EXIT_FAILURE;
lua_State *L = luaL_newstate(); /* create state */
if (L == NULL) {
openbuslua_logmessage(argv[0], "cannot create Lua state: not enough memory");
} else {
/* call 'pmain' in protected mode */
lua_pushcfunction(L, &pmain);
lua_pushinteger(L, argc); /* 1st argument */
lua_pushlightuserdata(L, argv); /* 2nd argument */
status = lua_pcall(L, 2, 1, 0);
if (status == LUA_OK) {
result = lua_tointeger(L, -1); /* get result */
} else {
const char *msg = (lua_type(L, -1) == LUA_TSTRING) ? lua_tostring(L, -1)
: NULL;
if (msg == NULL) msg = "(error object is not a string)";
openbuslua_logmessage(argv[0], msg);
lua_pop(L, 1);
}
lua_close(L);
openbuslua_setlogpath(NULL);
}
return result;
}
LIBRARY luaopenbus
EXPORTS
luapreload_luaopenbus
luaopen_openbus_util_database
luaopen_openbus_util_oo
luaopen_openbus_util_sysex
luaopen_openbus_core_legacy_parsed
luaopen_openbus_core_legacy_idl
luaopen_openbus_core_idl_parsed
luaopen_openbus_util_logger
luaopen_openbus_core_idl_makeaux
luaopen_openbus_util_autotable
luaopen_openbus_idl
luaopen_openbus_core_idl
luaopen_openbus
luaopen_openbus_util_tickets
luaopen_openbus_idl_parsed
luaopen_openbus_util_corba
luaopen_openbus_util_server
luaopen_openbus_util_messages
luaopen_openbus_util_argcheck
luaopen_openbus_core_messages
luaopen_openbus_assistant
luaopen_openbus_core_Access
PROJNAME= luaopenbus
LIBNAME= $(PROJNAME)
SRC= $(PRELOAD_DIR)/$(LIBNAME).c
SRC= \
openbuslua.c \
threadlib.c \
$(PRELOAD_DIR)/$(LIBNAME).c
OPENBUSSCSIDL= ${SCS_IDL1_2_HOME}/src
OPENBUSNEWIDL= ${OPENBUS_IDL2_1_HOME}/src
......@@ -32,7 +35,10 @@ LUASRC= \
$(LUADIR)/openbus/util/server.lua \
$(LUADIR)/openbus/util/sysex.lua \
$(LUADIR)/openbus/util/tickets.lua \
$(LUADIR)/openbus.lua
$(LUADIR)/openbus.lua \
threadlib.c \
$(LUADIR)/openbus/console/costdin.lua \
$(LUADIR)/openbus/console/utils.lua
LIBIDL= $(OPENBUSLIBIDL)/openbus.idl
......@@ -62,8 +68,55 @@ OLDDEPENDENTIDL= \
$(OPENBUSOLDIDL)/credential.idl \
$(OPENBUSSCSIDL)/scs.idl
LUAPRELOADFLAGS= -s
include ${OIL_HOME}/openbus/base.mak
LIBS:= \
luastruct \
luasocket \
luatuple \
loop \
luacothread \
luaidl \
oil \
luavararg \
lfs \
luuid \
lce \
luasec \
luascs
INCLUDES+= . \
$(LUASTRUCT_HOME)/src \
$(LUASOCKET_HOME)/include \
$(LUATUPLE_HOME)/obj/$(TEC_UNAME) \
$(LOOP_HOME)/obj/$(TEC_UNAME) \
$(LUACOTHREAD_HOME)/obj/$(TEC_UNAME) \
$(LUAIDL_HOME)/obj/$(TEC_UNAME) \
$(OIL_HOME)/obj/$(TEC_UNAME) \
$(LUAVARARG_HOME)/src \
$(LUAFILESYSTEM_HOME)/include \
$(LUUID_HOME)/include \
$(LCE_HOME)/include \
$(LUASEC_HOME)/include \
$(SCS_LUA_HOME)/obj/$(TEC_UNAME)
LDIR+= \
$(LUASTRUCT_HOME)/lib/$(TEC_UNAME) \
$(LUASOCKET_HOME)/lib/$(TEC_UNAME) \
$(LUATUPLE_HOME)/lib/$(TEC_UNAME) \
$(LOOP_HOME)/lib/$(TEC_UNAME) \
$(LUACOTHREAD_HOME)/lib/$(TEC_UNAME) \
$(LUAIDL_HOME)/lib/$(TEC_UNAME) \
$(OIL_HOME)/lib/$(TEC_UNAME) \
$(LUAVARARG_HOME)/lib/$(TEC