1 /*
2 * (c) 2010 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
3 * Alexander Warg <warg@os.inf.tu-dresden.de>
4 * economic rights: Technische Universität Dresden (Germany)
5 *
6 * This file is part of TUD:OS and distributed under the terms of the
7 * GNU General Public License 2.
8 * Please see the COPYING-GPL-2 file for details.
9 */
10
11 #include <l4/sys/err.h>
12 #include <l4/re/util/br_manager>
13 #include <l4/re/util/object_registry>
14 #include <l4/re/error_helper>
15 #include <l4/ned/cmd_control>
16
17 #include <lua.h>
18 #include <lauxlib.h>
19 #include <lualib.h>
20
21 #include <cstdio>
22 #include <cstring>
23 #include <unistd.h>
24 #include <getopt.h>
25
26 #include "lua_cap.h"
27 #include "lua.h"
28
29 static Lua::Lib *_lua_init;
30
31 extern char const _binary_ned_lua_start[];
32 extern char const _binary_ned_lua_end[];
33
_create_table(lua_State * l)34 static int _create_table(lua_State *l)
35 { lua_newtable(l); return 1; }
36
lua_require_module(lua_State * l,char const * name)37 void Lua::lua_require_module(lua_State *l, char const *name)
38 {
39 luaL_requiref(l, name, _create_table, 0);
40 }
41
Lib(Prio prio)42 Lua::Lib::Lib(Prio prio) : _prio(prio), _next(0)
43 {
44 Lib **f = &_lua_init;
45 while (*f && (*f)->prio() < prio)
46 f = &(*f)->_next;
47
48 _next = *f;
49 *f = this;
50 }
51
52 void
run_init(lua_State * l)53 Lua::Lib::run_init(lua_State *l)
54 {
55 for (Lib *c = _lua_init; c; c = c->_next)
56 c->init(l);
57 }
58
59
60 static const luaL_Reg libs[] =
61 {
62 { "_G", luaopen_base },
63 {LUA_LOADLIBNAME, luaopen_package},
64 {LUA_TABLIBNAME, luaopen_table},
65 // { LUA_IOLIBNAME, luaopen_io },
66 { LUA_STRLIBNAME, luaopen_string },
67 {LUA_LOADLIBNAME, luaopen_package},
68 {LUA_DBLIBNAME, luaopen_debug},
69 { NULL, NULL }
70 };
71
72 static char const *const options = "+e:c:";
73 static struct option const loptions[] =
74 {
75 { "execute", 1, NULL, 'e' },
76 { "cmdcap", 1, NULL, 'c' },
77 { 0, 0, 0, 0 }
78 };
79
80 static int
execute_lua_buf(lua_State * l,char const * buf,size_t sz,char const * name)81 execute_lua_buf(lua_State *l, char const *buf, size_t sz, char const *name)
82 {
83 if (luaL_loadbuffer(l, buf, sz, name))
84 {
85 fprintf(stderr, "lua error: %s.\n", lua_tostring(l, -1));
86 lua_pop(l, lua_gettop(l));
87 return 1;
88 }
89
90 if (lua_pcall(l, 0, 1, 0))
91 {
92 fprintf(stderr, "lua error: %s.\n", lua_tostring(l, -1));
93 lua_pop(l, lua_gettop(l));
94 return 1;
95 }
96
97 lua_pop(l, lua_gettop(l));
98
99 return 0;
100 }
101
102 class Command_dispatcher
103 : public L4::Epiface_t<Command_dispatcher, L4Re::Ned::Cmd_control>
104 {
105 public:
Command_dispatcher(lua_State * l)106 Command_dispatcher(lua_State *l) : _lua(l) {}
107
op_execute(L4Re::Ned::Cmd_control::Rights,L4::Ipc::String_in_buf<> cmd,L4::Ipc::Array_ref<char> & res)108 long op_execute(L4Re::Ned::Cmd_control::Rights,
109 L4::Ipc::String_in_buf<> cmd,
110 L4::Ipc::Array_ref<char> &res)
111 {
112 if (luaL_loadbuffer(_lua, cmd.data, cmd.length - 1, "argument"))
113 {
114 fprintf(stderr, "lua couldn't parse '%.*s': %s.\n", (int)cmd.length - 1,
115 cmd.data, lua_tostring(_lua, -1));
116 lua_pop(_lua, 1);
117
118 return -L4_EINVAL;
119 }
120
121 if (lua_pcall(_lua, 0, 1, 0))
122 {
123 // errors during Factory::create() are returned as a table with
124 // { "msg" = message, "code" = return value }
125 // extract error message from table and push it on the stack
126 if (lua_istable(_lua, -1))
127 lua_getfield(_lua, -1, "msg");
128
129 fprintf(stderr, "lua couldn't execute '%.*s': %s.\n", (int)cmd.length - 1,
130 cmd.data, lua_tostring(_lua, -1));
131 lua_pop(_lua, 1);
132
133 return -L4_EIO;
134 }
135
136 size_t len;
137 char const *res_txt = luaL_tolstring(_lua, -1, &len);
138 if (len > res.length)
139 len = res.length;
140
141 memcpy(res.data, res_txt, len);
142 res.length = len;
143
144 // drop the return value
145 lua_pop(_lua, lua_gettop(_lua));
146
147 return L4_EOK;
148 }
149
150 private:
151 lua_State *_lua;
152 };
153
154 namespace Lua { namespace {
155
__server_loop(lua_State * l)156 static int __server_loop(lua_State *l)
157 {
158 static bool once;
159
160 if (once)
161 return 0;
162 once = true;
163
164 Lua::Cap *n = check_cap(l, 1);
165
166 L4Re::Util::Registry_server<L4Re::Util::Br_manager_timeout_hooks> server;
167 Command_dispatcher cmd_dispatch(l);
168
169 L4Re::chkcap(server.registry()->register_obj(&cmd_dispatch,
170 n->cap<L4::Ipc_gate>().get()),
171 "Register command dispatcher endpoint.");
172
173 server.loop();
174
175 return 0;
176 }
177
178 class Lib_server : public Lib
179 {
180 public:
Lib_server()181 Lib_server() : Lib(P_env) {}
182
init(lua_State * l)183 void init(lua_State *l)
184 {
185 static const luaL_Reg _ops[] =
186 {
187 { "server_loop", __server_loop },
188 { NULL, NULL }
189 };
190 Lua::lua_require_module(l, "L4");
191 luaL_setfuncs(l, _ops, 0);
192 }
193 };
194 static Lib_server __libserver;
195
196 }}
197
lua(int argc,char const * const * argv)198 int lua(int argc, char const *const *argv)
199 {
200 printf("Ned says: Hi World!\n");
201
202 enum Mode { None, Cmd_channel };
203 Mode mode = None;
204
205 lua_State *L;
206 L = luaL_newstate();
207
208 if (!L)
209 return 1;
210
211 for (int i = 0; libs[i].func; ++i)
212 {
213 luaL_requiref(L, libs[i].name, libs[i].func, 1);
214 lua_pop(L, 1);
215 }
216
217 Lua::init_lua_cap(L);
218 Lua::Lib::run_init(L);
219
220 if (execute_lua_buf(L, _binary_ned_lua_start,
221 _binary_ned_lua_end - _binary_ned_lua_start,
222 "@ned.lua"))
223 return 0;
224
225 int opt;
226 char const *cmd_client = 0;
227 while ((opt = getopt_long(argc, const_cast<char *const*>(argv),
228 options, loptions, NULL)) != -1)
229 {
230 switch (opt)
231 {
232 case 'e':
233 {
234 int err = execute_lua_buf(L, optarg, strlen(optarg), optarg);
235 if (err)
236 fprintf(stderr, "Error executing cmdline statement\n");
237 break;
238 }
239 case 'c':
240 cmd_client = optarg;
241 mode = Cmd_channel;
242 break;
243 default: break;
244 }
245 }
246
247 // everything following the first non-option argument is considered an
248 // argument for the Lua script and added to the 'arg' table
249 // The script name itself is passed as arg[0].
250 if (argc > optind)
251 {
252 if (!_create_table(L))
253 {
254 fprintf(stderr, "lua error: %s.\n", lua_tostring(L, -1));
255 lua_pop(L, lua_gettop(L));
256 return 0;
257 }
258
259 unsigned arg_idx = 0;
260 for (int c = optind; c < argc; ++c, ++arg_idx)
261 {
262 lua_pushinteger(L, arg_idx);
263 lua_pushstring(L, argv[c]);
264 lua_settable(L, -3);
265 }
266 lua_setglobal(L, "arg");
267 }
268
269 printf("Ned: loading file: '%s'\n", argv[optind]);
270 int e = luaL_dofile(L, argv[optind]);
271 if (e)
272 {
273 // errors during Factory::create() are returned as a table with
274 // { "msg" = message, "code" = return value }
275 // extract error message from table and push it on the stack
276 if (lua_istable(L, -1))
277 lua_getfield(L, -1, "msg");
278
279 fprintf(stderr, "lua error: %s.\n", lua_tostring(L, -1));
280 }
281
282 lua_gc(L, LUA_GCCOLLECT, 0);
283
284 if (mode == Cmd_channel)
285 {
286 L4Re::Util::Registry_server<L4Re::Util::Br_manager_timeout_hooks> server;
287 Command_dispatcher cmd_dispatch(L);
288
289 server.registry()->register_obj(&cmd_dispatch, cmd_client);
290
291 server.loop();
292 }
293
294 return 0;
295 }
296