]> git.proxmox.com Git - ceph.git/blob - ceph/src/cls/lua/cls_lua.cc
add subtree-ish sources for 12.0.3
[ceph.git] / ceph / src / cls / lua / cls_lua.cc
1 /*
2 * Lua Bindings for RADOS Object Class
3 */
4 #include <errno.h>
5 #include <setjmp.h>
6 #include <string>
7 #include <sstream>
8 #include <lua.hpp>
9 #include "include/types.h"
10 #include "objclass/objclass.h"
11 #include "json_spirit/json_spirit.h"
12 #include "cls_lua.h"
13 #include "cls_lua_ops.h"
14
15 CLS_VER(1,0)
16 CLS_NAME(lua)
17
18 /*
19 * Jump point for recovering from Lua panic.
20 */
21 static jmp_buf cls_lua_panic_jump;
22
23 /*
24 * Handle Lua panic.
25 */
26 static int cls_lua_atpanic(lua_State *lua)
27 {
28 CLS_ERR("error: Lua panic: %s", lua_tostring(lua, -1));
29 longjmp(cls_lua_panic_jump, 1);
30 return 0;
31 }
32
33 struct clslua_err {
34 bool error;
35 int ret;
36 };
37
38 /*
39 * Input parameter encoding.
40 */
41 enum InputEncoding {
42 JSON_ENC,
43 BUFFERLIST_ENC,
44 };
45
46 struct clslua_hctx {
47 struct clslua_err error;
48 InputEncoding in_enc;
49 int ret;
50
51 cls_method_context_t *hctx;
52 bufferlist *inbl; // raw cls input
53 bufferlist *outbl; // raw cls output
54
55 string script; // lua script
56 string handler; // lua handler
57 bufferlist input; // lua handler input
58 };
59
60 /* Lua registry key for method context */
61 static char clslua_hctx_reg_key;
62
63 /*
64 * Grabs the full method handler context
65 */
66 static clslua_hctx *__clslua_get_hctx(lua_State *L)
67 {
68 /* lookup registry value */
69 lua_pushlightuserdata(L, &clslua_hctx_reg_key);
70 lua_gettable(L, LUA_REGISTRYINDEX);
71
72 /* check cls_lua assumptions */
73 assert(!lua_isnil(L, -1));
74 assert(lua_type(L, -1) == LUA_TLIGHTUSERDATA);
75
76 /* cast and cleanup stack */
77 clslua_hctx *hctx = (struct clslua_hctx *)lua_touserdata(L, -1);
78 lua_pop(L, 1);
79
80 return hctx;
81 }
82
83 /*
84 * Get the method context out of the registry. This is called at the beginning
85 * of each clx_cxx_* wrapper, and must be set before there is any chance a Lua
86 * script calling a 'cls' module function that requires it.
87 */
88 static cls_method_context_t clslua_get_hctx(lua_State *L)
89 {
90 struct clslua_hctx *hctx = __clslua_get_hctx(L);
91 return *hctx->hctx;
92 }
93
94 /*
95 * Returns a reference to cls_lua error state from registry.
96 */
97 struct clslua_err *clslua_checkerr(lua_State *L)
98 {
99 struct clslua_hctx *hctx = __clslua_get_hctx(L);
100 struct clslua_err *err = &hctx->error;
101 return err;
102 }
103
104
105 /* Registry key for real `pcall` function */
106 static char clslua_pcall_reg_key;
107
108 /*
109 * Wrap Lua pcall to check for errors thrown by cls_lua (e.g. I/O errors or
110 * bufferlist decoding errors). The global error is cleared before returning
111 * to the caller.
112 */
113 static int clslua_pcall(lua_State *L)
114 {
115 int nargs = lua_gettop(L);
116 lua_pushlightuserdata(L, &clslua_pcall_reg_key);
117 lua_gettable(L, LUA_REGISTRYINDEX);
118 lua_insert(L, 1);
119 lua_call(L, nargs, LUA_MULTRET);
120 struct clslua_err *err = clslua_checkerr(L);
121 assert(err);
122 if (err->error) {
123 err->error = false;
124 lua_pushinteger(L, err->ret);
125 lua_insert(L, -2);
126 }
127 return lua_gettop(L);
128 }
129
130
131 /*
132 * cls_log
133 */
134 static int clslua_log(lua_State *L)
135 {
136 int nargs = lua_gettop(L);
137
138 if (!nargs)
139 return 0;
140
141 int loglevel = LOG_LEVEL_DEFAULT;
142 bool custom_ll = false;
143
144 /* check if first arg can be a log level */
145 if (nargs > 1 && lua_isnumber(L, 1)) {
146 int ll = (int)lua_tonumber(L, 1);
147 if (ll >= 0) {
148 loglevel = ll;
149 custom_ll = true;
150 }
151 }
152
153 /* check space for args and seperators (" ") */
154 int nelems = ((nargs - (custom_ll ? 1 : 0)) * 2) - 1;
155 luaL_checkstack(L, nelems, "rados.log(..)");
156
157 for (int i = custom_ll ? 2 : 1; i <= nargs; i++) {
158 const char *part = lua_tostring(L, i);
159 if (!part) {
160 if (lua_type(L, i) == LUA_TBOOLEAN)
161 part = lua_toboolean(L, i) ? "true" : "false";
162 else
163 part = luaL_typename(L, i);
164 }
165 lua_pushstring(L, part);
166 if ((i+1) <= nargs)
167 lua_pushstring(L, " ");
168 }
169
170 /* join string parts and send to Ceph/reply log */
171 lua_concat(L, nelems);
172 CLS_LOG(loglevel, "%s", lua_tostring(L, -1));
173
174 /* concat leaves result at top of stack */
175 return 1;
176 }
177
178 static char clslua_registered_handle_reg_key;
179
180 /*
181 * Register a function to be used as a handler target
182 */
183 static int clslua_register(lua_State *L)
184 {
185 luaL_checktype(L, 1, LUA_TFUNCTION);
186
187 /* get table of registered handlers */
188 lua_pushlightuserdata(L, &clslua_registered_handle_reg_key);
189 lua_gettable(L, LUA_REGISTRYINDEX);
190 assert(lua_type(L, -1) == LUA_TTABLE);
191
192 /* lookup function argument */
193 lua_pushvalue(L, 1);
194 lua_gettable(L, -2);
195
196 if (lua_isnil(L, -1)) {
197 lua_pushvalue(L, 1);
198 lua_pushvalue(L, 1);
199 lua_settable(L, -4);
200 } else {
201 lua_pushstring(L, "Cannot register handler more than once");
202 return lua_error(L);
203 }
204
205 return 0;
206 }
207
208 /*
209 * Check if a function is registered as a handler
210 */
211 static void clslua_check_registered_handler(lua_State *L)
212 {
213 luaL_checktype(L, -1, LUA_TFUNCTION);
214
215 /* get table of registered handlers */
216 lua_pushlightuserdata(L, &clslua_registered_handle_reg_key);
217 lua_gettable(L, LUA_REGISTRYINDEX);
218 assert(lua_type(L, -1) == LUA_TTABLE);
219
220 /* lookup function argument */
221 lua_pushvalue(L, -2);
222 lua_gettable(L, -2);
223
224 if (!lua_rawequal(L, -1, -3)) {
225 lua_pushstring(L, "Handler is not registered");
226 lua_error(L);
227 }
228
229 lua_pop(L, 2);
230 }
231
232 /*
233 * Handle result of a cls_cxx_* call. If @ok is non-zero then we return with
234 * the number of Lua return arguments on the stack. Otherwise we save error
235 * information in the registry and throw a Lua error.
236 */
237 static int clslua_opresult(lua_State *L, int ok, int ret, int nargs,
238 bool error_on_stack = false)
239 {
240 struct clslua_err *err = clslua_checkerr(L);
241
242 assert(err);
243 if (err->error) {
244 CLS_ERR("error: cls_lua state machine: unexpected error");
245 ceph_abort();
246 }
247
248 /* everything is cherry */
249 if (ok)
250 return nargs;
251
252 /* set error in registry */
253 err->error = true;
254 err->ret = ret;
255
256 /* push error message */
257 if (!error_on_stack)
258 lua_pushfstring(L, "%s", strerror(-ret));
259
260 return lua_error(L);
261 }
262
263 /*
264 * cls_cxx_create
265 */
266 static int clslua_create(lua_State *lua)
267 {
268 cls_method_context_t hctx = clslua_get_hctx(lua);
269 int exclusive = lua_toboolean(lua, 1);
270
271 int ret = cls_cxx_create(hctx, exclusive);
272 return clslua_opresult(lua, (ret == 0), ret, 0);
273 }
274
275 /*
276 * cls_cxx_remove
277 */
278 static int clslua_remove(lua_State *lua)
279 {
280 cls_method_context_t hctx = clslua_get_hctx(lua);
281
282 int ret = cls_cxx_remove(hctx);
283 return clslua_opresult(lua, (ret == 0), ret, 0);
284 }
285
286 /*
287 * cls_cxx_stat
288 */
289 static int clslua_stat(lua_State *L)
290 {
291 cls_method_context_t hctx = clslua_get_hctx(L);
292
293 uint64_t size;
294 time_t mtime;
295 int ret = cls_cxx_stat(hctx, &size, &mtime);
296 if (!ret) {
297 lua_pushinteger(L, size);
298 lua_pushinteger(L, mtime);
299 }
300 return clslua_opresult(L, (ret == 0), ret, 2);
301 }
302
303 /*
304 * cls_cxx_read
305 */
306 static int clslua_read(lua_State *L)
307 {
308 cls_method_context_t hctx = clslua_get_hctx(L);
309 int offset = luaL_checkinteger(L, 1);
310 int length = luaL_checkinteger(L, 2);
311 bufferlist *bl = clslua_pushbufferlist(L, NULL);
312 int ret = cls_cxx_read(hctx, offset, length, bl);
313 return clslua_opresult(L, (ret >= 0), ret, 1);
314 }
315
316 /*
317 * cls_cxx_write
318 */
319 static int clslua_write(lua_State *L)
320 {
321 cls_method_context_t hctx = clslua_get_hctx(L);
322 int offset = luaL_checkinteger(L, 1);
323 int length = luaL_checkinteger(L, 2);
324 bufferlist *bl = clslua_checkbufferlist(L, 3);
325 int ret = cls_cxx_write(hctx, offset, length, bl);
326 return clslua_opresult(L, (ret == 0), ret, 0);
327 }
328
329 /*
330 * cls_cxx_write_full
331 */
332 static int clslua_write_full(lua_State *L)
333 {
334 cls_method_context_t hctx = clslua_get_hctx(L);
335 bufferlist *bl = clslua_checkbufferlist(L, 1);
336 int ret = cls_cxx_write_full(hctx, bl);
337 return clslua_opresult(L, (ret == 0), ret, 0);
338 }
339
340 /*
341 * cls_cxx_getxattr
342 */
343 static int clslua_getxattr(lua_State *L)
344 {
345 cls_method_context_t hctx = clslua_get_hctx(L);
346 const char *name = luaL_checkstring(L, 1);
347 bufferlist *bl = clslua_pushbufferlist(L, NULL);
348 int ret = cls_cxx_getxattr(hctx, name, bl);
349 return clslua_opresult(L, (ret >= 0), ret, 1);
350 }
351
352 /*
353 * cls_cxx_getxattrs
354 */
355 static int clslua_getxattrs(lua_State *L)
356 {
357 cls_method_context_t hctx = clslua_get_hctx(L);
358
359 map<string, bufferlist> attrs;
360 int ret = cls_cxx_getxattrs(hctx, &attrs);
361 if (ret < 0)
362 return clslua_opresult(L, 0, ret, 0);
363
364 lua_createtable(L, 0, attrs.size());
365
366 for (auto it = attrs.cbegin(); it != attrs.cend(); it++) {
367 lua_pushstring(L, it->first.c_str());
368 bufferlist *bl = clslua_pushbufferlist(L, NULL);
369 *bl = it->second; // xfer ownership... will be GC'd
370 lua_settable(L, -3);
371 }
372
373 return clslua_opresult(L, 1, ret, 1);
374 }
375
376 /*
377 * cls_cxx_setxattr
378 */
379 static int clslua_setxattr(lua_State *L)
380 {
381 cls_method_context_t hctx = clslua_get_hctx(L);
382 const char *name = luaL_checkstring(L, 1);
383 bufferlist *bl = clslua_checkbufferlist(L, 2);
384 int ret = cls_cxx_setxattr(hctx, name, bl);
385 return clslua_opresult(L, (ret == 0), ret, 1);
386 }
387
388 /*
389 * cls_cxx_map_get_val
390 */
391 static int clslua_map_get_val(lua_State *L)
392 {
393 cls_method_context_t hctx = clslua_get_hctx(L);
394 const char *key = luaL_checkstring(L, 1);
395 bufferlist *bl = clslua_pushbufferlist(L, NULL);
396 int ret = cls_cxx_map_get_val(hctx, key, bl);
397 return clslua_opresult(L, (ret == 0), ret, 1);
398 }
399
400 /*
401 * cls_cxx_map_set_val
402 */
403 static int clslua_map_set_val(lua_State *L)
404 {
405 cls_method_context_t hctx = clslua_get_hctx(L);
406 const char *key = luaL_checkstring(L, 1);
407 bufferlist *val = clslua_checkbufferlist(L, 2);
408 int ret = cls_cxx_map_set_val(hctx, key, val);
409 return clslua_opresult(L, (ret == 0), ret, 0);
410 }
411
412 /*
413 * cls_cxx_map_clear
414 */
415 static int clslua_map_clear(lua_State *L)
416 {
417 cls_method_context_t hctx = clslua_get_hctx(L);
418 int ret = cls_cxx_map_clear(hctx);
419 return clslua_opresult(L, (ret == 0), ret, 0);
420 }
421
422 /*
423 * cls_cxx_map_get_keys
424 */
425 static int clslua_map_get_keys(lua_State *L)
426 {
427 cls_method_context_t hctx = clslua_get_hctx(L);
428 const char *start_after = luaL_checkstring(L, 1);
429 int max_to_get = luaL_checkinteger(L, 2);
430
431 std::set<string> keys;
432 int ret = cls_cxx_map_get_keys(hctx, start_after, max_to_get, &keys);
433 if (ret < 0)
434 return clslua_opresult(L, 0, ret, 0);
435
436 lua_createtable(L, 0, keys.size());
437
438 for (auto it = keys.cbegin(); it != keys.cend(); it++) {
439 const std::string& key = *it;
440 lua_pushstring(L, key.c_str());
441 lua_pushboolean(L, 1);
442 lua_settable(L, -3);
443 }
444
445 return clslua_opresult(L, 1, ret, 1);
446 }
447
448 /*
449 * cls_cxx_map_get_vals
450 */
451 static int clslua_map_get_vals(lua_State *L)
452 {
453 cls_method_context_t hctx = clslua_get_hctx(L);
454 const char *start_after = luaL_checkstring(L, 1);
455 const char *filter_prefix= luaL_checkstring(L, 2);
456 int max_to_get = luaL_checkinteger(L, 3);
457
458 map<string, bufferlist> kvpairs;
459 int ret = cls_cxx_map_get_vals(hctx, start_after, filter_prefix,
460 max_to_get, &kvpairs);
461 if (ret < 0)
462 return clslua_opresult(L, 0, ret, 0);
463
464 lua_createtable(L, 0, kvpairs.size());
465
466 for (auto it = kvpairs.cbegin(); it != kvpairs.cend(); it++) {
467 lua_pushstring(L, it->first.c_str());
468 bufferlist *bl = clslua_pushbufferlist(L, NULL);
469 *bl = it->second; // xfer ownership... will be GC'd
470 lua_settable(L, -3);
471 }
472
473 return clslua_opresult(L, 1, ret, 1);
474 }
475
476 /*
477 * cls_cxx_map_read_header
478 */
479 static int clslua_map_read_header(lua_State *L)
480 {
481 cls_method_context_t hctx = clslua_get_hctx(L);
482 bufferlist *bl = clslua_pushbufferlist(L, NULL);
483 int ret = cls_cxx_map_read_header(hctx, bl);
484 return clslua_opresult(L, (ret >= 0), ret, 1);
485 }
486
487 /*
488 * cls_cxx_map_write_header
489 */
490 static int clslua_map_write_header(lua_State *L)
491 {
492 cls_method_context_t hctx = clslua_get_hctx(L);
493 bufferlist *bl = clslua_checkbufferlist(L, 1);
494 int ret = cls_cxx_map_write_header(hctx, bl);
495 return clslua_opresult(L, (ret == 0), ret, 0);
496 }
497
498 /*
499 * cls_cxx_map_set_vals
500 */
501 static int clslua_map_set_vals(lua_State *L)
502 {
503 cls_method_context_t hctx = clslua_get_hctx(L);
504 luaL_checktype(L, 1, LUA_TTABLE);
505
506 map<string, bufferlist> kvpairs;
507
508 for (lua_pushnil(L); lua_next(L, 1); lua_pop(L, 1)) {
509 /*
510 * In the case of a numeric key a copy is made on the stack because
511 * converting to a string would otherwise manipulate the original key and
512 * cause problems for iteration.
513 */
514 string key;
515 int type_code = lua_type(L, -2);
516 switch (type_code) {
517 case LUA_TSTRING:
518 key.assign(lua_tolstring(L, -2, NULL));
519 break;
520
521 case LUA_TNUMBER:
522 lua_pushvalue(L, -2);
523 key.assign(lua_tolstring(L, -1, NULL));
524 lua_pop(L, 1);
525 break;
526
527 default:
528 lua_pushfstring(L, "map_set_vals: invalid key type (%s)",
529 lua_typename(L, type_code));
530 return clslua_opresult(L, 0, -EINVAL, 0, true);
531 }
532
533 bufferlist val;
534 type_code = lua_type(L, -1);
535 switch (type_code) {
536 case LUA_TSTRING:
537 {
538 size_t len;
539 const char *data = lua_tolstring(L, -1, &len);
540 val.append(data, len);
541 }
542 break;
543
544 default:
545 lua_pushfstring(L, "map_set_vals: invalid val type (%s) for key (%s)",
546 lua_typename(L, type_code), key.c_str());
547 return clslua_opresult(L, 0, -EINVAL, 0, true);
548 }
549
550 kvpairs[key] = val;
551 }
552
553 int ret = cls_cxx_map_set_vals(hctx, &kvpairs);
554
555 return clslua_opresult(L, (ret == 0), ret, 0);
556 }
557
558 /*
559 * cls_cxx_map_remove_key
560 */
561 static int clslua_map_remove_key(lua_State *L)
562 {
563 cls_method_context_t hctx = clslua_get_hctx(L);
564 const char *key = luaL_checkstring(L, 1);
565 int ret = cls_cxx_map_remove_key(hctx, key);
566 return clslua_opresult(L, (ret == 0), ret, 0);
567 }
568
569 /*
570 * cls_current_version
571 */
572 static int clslua_current_version(lua_State *L)
573 {
574 cls_method_context_t hctx = clslua_get_hctx(L);
575 uint64_t version = cls_current_version(hctx);
576 lua_pushinteger(L, version);
577 return clslua_opresult(L, 1, 0, 1);
578 }
579
580 /*
581 * cls_current_subop_num
582 */
583 static int clslua_current_subop_num(lua_State *L)
584 {
585 cls_method_context_t hctx = clslua_get_hctx(L);
586 int num = cls_current_subop_num(hctx);
587 lua_pushinteger(L, num);
588 return clslua_opresult(L, 1, 0, 1);
589 }
590
591 /*
592 * cls_current_subop_version
593 */
594 static int clslua_current_subop_version(lua_State *L)
595 {
596 cls_method_context_t hctx = clslua_get_hctx(L);
597 string s;
598 cls_cxx_subop_version(hctx, &s);
599 lua_pushstring(L, s.c_str());
600 return clslua_opresult(L, 1, 0, 1);
601 }
602
603 /*
604 * Functions registered in the 'cls' module.
605 */
606 static const luaL_Reg clslua_lib[] = {
607 // mgmt
608 {"register", clslua_register},
609 {"log", clslua_log},
610
611 // data
612 {"create", clslua_create},
613 {"remove", clslua_remove},
614 {"stat", clslua_stat},
615 {"read", clslua_read},
616 {"write", clslua_write},
617 {"write_full", clslua_write_full},
618
619 // xattr
620 {"getxattr", clslua_getxattr},
621 {"getxattrs", clslua_getxattrs},
622 {"setxattr", clslua_setxattr},
623
624 // omap
625 {"map_clear", clslua_map_clear},
626 {"map_get_keys", clslua_map_get_keys},
627 {"map_get_vals", clslua_map_get_vals},
628 {"map_read_header", clslua_map_read_header},
629 {"map_write_header", clslua_map_write_header},
630 {"map_get_val", clslua_map_get_val},
631 {"map_set_val", clslua_map_set_val},
632 {"map_set_vals", clslua_map_set_vals},
633 {"map_remove_key", clslua_map_remove_key},
634
635 // env
636 {"current_version", clslua_current_version},
637 {"current_subop_num", clslua_current_subop_num},
638 {"current_subop_version", clslua_current_subop_version},
639
640 {NULL, NULL}
641 };
642
643 /*
644 * Set int const in table at top of stack
645 */
646 #define SET_INT_CONST(var) do { \
647 lua_pushinteger(L, var); \
648 lua_setfield(L, -2, #var); \
649 } while (0)
650
651 /*
652 *
653 */
654 static int luaopen_objclass(lua_State *L)
655 {
656 lua_newtable(L);
657
658 /*
659 * Register cls functions (cls.log, etc...)
660 */
661 luaL_setfuncs(L, clslua_lib, 0);
662
663 /*
664 * Register generic errno values under 'cls'
665 */
666 SET_INT_CONST(EPERM);
667 SET_INT_CONST(ENOENT);
668 SET_INT_CONST(ESRCH);
669 SET_INT_CONST(EINTR);
670 SET_INT_CONST(EIO);
671 SET_INT_CONST(ENXIO);
672 SET_INT_CONST(E2BIG);
673 SET_INT_CONST(ENOEXEC);
674 SET_INT_CONST(EBADF);
675 SET_INT_CONST(ECHILD);
676 SET_INT_CONST(EAGAIN);
677 SET_INT_CONST(ENOMEM);
678 SET_INT_CONST(EACCES);
679 SET_INT_CONST(EFAULT);
680 SET_INT_CONST(EBUSY);
681 SET_INT_CONST(EEXIST);
682 SET_INT_CONST(EXDEV);
683 SET_INT_CONST(ENODEV);
684 SET_INT_CONST(ENOTDIR);
685 SET_INT_CONST(EISDIR);
686 SET_INT_CONST(EINVAL);
687 SET_INT_CONST(ENFILE);
688 SET_INT_CONST(EMFILE);
689 SET_INT_CONST(ENOTTY);
690 SET_INT_CONST(EFBIG);
691 SET_INT_CONST(ENOSPC);
692 SET_INT_CONST(ESPIPE);
693 SET_INT_CONST(EROFS);
694 SET_INT_CONST(EMLINK);
695 SET_INT_CONST(EPIPE);
696 SET_INT_CONST(EDOM);
697 SET_INT_CONST(ERANGE);
698
699 return 1;
700 }
701
702 /*
703 * Setup the execution environment. Our sandbox currently is not
704 * sophisticated. With a new Lua state per-request we don't need to work about
705 * users stepping on each other, but we do rip out access to the local file
706 * system. All this will change when/if we decide to use some shared Lua
707 * states, most likely for performance reasons.
708 */
709 static void clslua_setup_env(lua_State *L)
710 {
711 luaL_requiref(L, "_G", luaopen_base, 1);
712 lua_pop(L, 1);
713
714 /*
715 * Wrap `pcall` to intercept errors. First save a reference to the default
716 * Lua `pcall` function, and then replace `pcall` with our version.
717 */
718 lua_pushlightuserdata(L, &clslua_pcall_reg_key);
719 lua_getglobal(L, "pcall");
720 lua_settable(L, LUA_REGISTRYINDEX);
721
722 lua_pushcfunction(L, clslua_pcall);
723 lua_setglobal(L, "pcall");
724
725 /* mask unsafe */
726 lua_pushnil(L);
727 lua_setglobal(L, "loadfile");
728
729 /* mask unsafe */
730 lua_pushnil(L);
731 lua_setglobal(L, "dofile");
732
733 /* not integrated into our error handling */
734 lua_pushnil(L);
735 lua_setglobal(L, "xpcall");
736
737 luaL_requiref(L, LUA_TABLIBNAME, luaopen_table, 1);
738 lua_pop(L, 1);
739
740 luaL_requiref(L, LUA_STRLIBNAME, luaopen_string, 1);
741 lua_pop(L, 1);
742
743 luaL_requiref(L, LUA_MATHLIBNAME, luaopen_math, 1);
744 lua_pop(L, 1);
745
746 luaL_requiref(L, "objclass", luaopen_objclass, 1);
747 lua_pop(L, 1);
748
749 luaL_requiref(L, "bufferlist", luaopen_bufferlist, 1);
750 lua_pop(L, 1);
751 }
752
753 /*
754 * Schema:
755 * {
756 * "script": "...",
757 * "handler": "...",
758 * "input": "..." # optional
759 * }
760 */
761 static int unpack_json_command(lua_State *L, struct clslua_hctx *ctx,
762 std::string& script, std::string& handler, std::string& input,
763 size_t *input_len)
764 {
765 std::string json_input(ctx->inbl->c_str());
766 json_spirit::mValue value;
767
768 if (!json_spirit::read(json_input, value)) {
769 CLS_ERR("error: unparseable JSON");
770 ctx->ret = -EINVAL;
771 return 1;
772 }
773
774 if (value.type() != json_spirit::obj_type) {
775 CLS_ERR("error: input not a JSON object");
776 ctx->ret = -EINVAL;
777 return 1;
778 }
779 json_spirit::mObject obj = value.get_obj();
780
781 // grab the script
782 std::map<std::string, json_spirit::mValue>::const_iterator it = obj.find("script");
783 if (it == obj.end()) {
784 CLS_ERR("error: 'script' field found in JSON object");
785 ctx->ret = -EINVAL;
786 return 1;
787 }
788
789 if (it->second.type() != json_spirit::str_type) {
790 CLS_ERR("error: script is not a string");
791 ctx->ret = -EINVAL;
792 return 1;
793 }
794 script = it->second.get_str();
795
796 // grab the target function/handler name
797 it = obj.find("handler");
798 if (it == obj.end()) {
799 CLS_ERR("error: no target handler found in JSON object");
800 ctx->ret = -EINVAL;
801 return 1;
802 }
803
804 if (it->second.type() != json_spirit::str_type) {
805 CLS_ERR("error: target handler is not a string");
806 ctx->ret = -EINVAL;
807 return 1;
808 }
809 handler = it->second.get_str();
810
811 // grab the input (optional)
812 it = obj.find("input");
813 if (it != obj.end()) {
814 if (it->second.type() != json_spirit::str_type) {
815 CLS_ERR("error: handler input is not a string");
816 ctx->ret = -EINVAL;
817 return 1;
818 }
819 input = it->second.get_str();
820 *input_len = input.size();
821 }
822
823 return 0;
824 }
825
826 /*
827 * Runs the script, and calls handler.
828 */
829 static int clslua_eval(lua_State *L)
830 {
831 struct clslua_hctx *ctx = __clslua_get_hctx(L);
832 ctx->ret = -EIO; /* assume failure */
833
834 /*
835 * Load modules, errno value constants, and other environment goodies. Must
836 * be done before loading/compiling the chunk.
837 */
838 clslua_setup_env(L);
839
840 /*
841 * Deserialize the input that contains the script, the name of the handler
842 * to call, and the handler input.
843 */
844 switch (ctx->in_enc) {
845 case JSON_ENC:
846 {
847 std::string input_str;
848 size_t input_str_len = 0;
849
850 // if there is an error decoding json then ctx->ret will be set and we
851 // return normally from this function.
852 if (unpack_json_command(L, ctx, ctx->script, ctx->handler, input_str,
853 &input_str_len))
854 return 0;
855
856 bufferptr bp(input_str.c_str(), input_str_len);
857 ctx->input.push_back(bp);
858 }
859 break;
860
861 case BUFFERLIST_ENC:
862 {
863 cls_lua_eval_op op;
864
865 try {
866 bufferlist::iterator it = ctx->inbl->begin();
867 ::decode(op, it);
868 } catch (const buffer::error &err) {
869 CLS_ERR("error: could not decode ceph encoded input");
870 ctx->ret = -EINVAL;
871 return 0;
872 }
873
874 ctx->script.swap(op.script);
875 ctx->handler.swap(op.handler);
876 ctx->input = op.input;
877 }
878 break;
879
880 default:
881 CLS_ERR("error: unknown encoding type");
882 ctx->ret = -EFAULT;
883 ceph_abort();
884 return 0;
885 }
886
887 /*
888 * Create table to hold registered (valid) handlers.
889 *
890 * Must be done before running the script for the first time because the
891 * script will immediately try to register one or more handlers using
892 * cls.register(function), which depends on this table.
893 */
894 lua_pushlightuserdata(L, &clslua_registered_handle_reg_key);
895 lua_newtable(L);
896 lua_settable(L, LUA_REGISTRYINDEX);
897
898 /* load and compile chunk */
899 if (luaL_loadstring(L, ctx->script.c_str()))
900 return lua_error(L);
901
902 /* execute chunk */
903 lua_call(L, 0, 0);
904
905 /* no error, but nothing left to do */
906 if (!ctx->handler.size()) {
907 CLS_LOG(10, "no handler name provided");
908 ctx->ret = 0; /* success */
909 return 0;
910 }
911
912 lua_getglobal(L, ctx->handler.c_str());
913 if (lua_type(L, -1) != LUA_TFUNCTION) {
914 CLS_ERR("error: unknown handler or not function: %s", ctx->handler.c_str());
915 ctx->ret = -EOPNOTSUPP;
916 return 0;
917 }
918
919 /* throw error if function is not registered */
920 clslua_check_registered_handler(L);
921
922 /* setup the input/output bufferlists */
923 clslua_pushbufferlist(L, &ctx->input);
924 clslua_pushbufferlist(L, ctx->outbl);
925
926 /*
927 * Call the target Lua object class handler. If the call is successful then
928 * we will examine the return value here and store it in the context. Errors
929 * that occur are handled in the top-level eval() function.
930 */
931 int top = lua_gettop(L);
932 lua_call(L, 2, LUA_MULTRET);
933
934 /* store return value in context */
935 if (!(lua_gettop(L) + 3 - top))
936 lua_pushinteger(L, 0);
937 ctx->ret = luaL_checkinteger(L, -1);
938
939 return 0;
940 }
941
942 /*
943 * Main handler. Proxies the Lua VM and the Lua-defined handler.
944 */
945 static int eval_generic(cls_method_context_t hctx, bufferlist *in, bufferlist *out,
946 InputEncoding in_enc)
947 {
948 struct clslua_hctx ctx;
949 lua_State *L = NULL;
950 int ret = -EIO;
951
952 /* stash context for use in Lua VM */
953 ctx.hctx = &hctx;
954 ctx.inbl = in;
955 ctx.in_enc = in_enc;
956 ctx.outbl = out;
957 ctx.error.error = false;
958
959 /* build lua vm state */
960 L = luaL_newstate();
961 if (!L) {
962 CLS_ERR("error creating new Lua state");
963 goto out;
964 }
965
966 /* panic handler for unhandled errors */
967 lua_atpanic(L, &cls_lua_atpanic);
968
969 if (setjmp(cls_lua_panic_jump) == 0) {
970
971 /*
972 * Stash the handler context in the register. It contains the objclass
973 * method context, global error state, and the command and reply structs.
974 */
975 lua_pushlightuserdata(L, &clslua_hctx_reg_key);
976 lua_pushlightuserdata(L, &ctx);
977 lua_settable(L, LUA_REGISTRYINDEX);
978
979 /* Process the input and run the script */
980 lua_pushcfunction(L, clslua_eval);
981 ret = lua_pcall(L, 0, 0, 0);
982
983 /* Encountered an error? */
984 if (ret) {
985 struct clslua_err *err = clslua_checkerr(L);
986 if (!err) {
987 CLS_ERR("error: cls_lua state machine: unexpected error");
988 ceph_abort();
989 }
990
991 /* Error origin a cls_cxx_* method? */
992 if (err->error) {
993 ret = err->ret; /* cls_cxx_* return value */
994
995 /* Errors always abort. Fix up ret and log error */
996 if (ret >= 0) {
997 CLS_ERR("error: unexpected handler return value");
998 ret = -EFAULT;
999 }
1000
1001 } else
1002 ret = -EIO; /* Generic error code */
1003
1004 CLS_ERR("error: %s", lua_tostring(L, -1));
1005
1006 } else {
1007 /*
1008 * No Lua error encountered while running the script, but the handler
1009 * may still have returned an error code (e.g. an errno value).
1010 */
1011 ret = ctx.ret;
1012 }
1013
1014 } else {
1015 CLS_ERR("error: recovering from Lua panic");
1016 ret = -EFAULT;
1017 }
1018
1019 out:
1020 if (L)
1021 lua_close(L);
1022 return ret;
1023 }
1024
1025 static int eval_json(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
1026 {
1027 return eval_generic(hctx, in, out, JSON_ENC);
1028 }
1029
1030 static int eval_bufferlist(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
1031 {
1032 return eval_generic(hctx, in, out, BUFFERLIST_ENC);
1033 }
1034
1035 CLS_INIT(lua)
1036 {
1037 CLS_LOG(20, "Loaded lua class!");
1038
1039 cls_handle_t h_class;
1040 cls_method_handle_t h_eval_json;
1041 cls_method_handle_t h_eval_bufferlist;
1042
1043 cls_register("lua", &h_class);
1044
1045 cls_register_cxx_method(h_class, "eval_json",
1046 CLS_METHOD_RD | CLS_METHOD_WR, eval_json, &h_eval_json);
1047
1048 cls_register_cxx_method(h_class, "eval_bufferlist",
1049 CLS_METHOD_RD | CLS_METHOD_WR, eval_bufferlist, &h_eval_bufferlist);
1050 }