klish_lua.c 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453
  1. #include <locale.h>
  2. #include <unistd.h>
  3. #include <stdlib.h>
  4. #include <errno.h>
  5. #include <sys/wait.h>
  6. #include <signal.h>
  7. #include <assert.h>
  8. #include <string.h>
  9. #include <klish/kplugin.h>
  10. #include <klish/kcontext.h>
  11. #include <faux/ini.h>
  12. #include <faux/str.h>
  13. #include <lua.h>
  14. #include <lualib.h>
  15. #include <lauxlib.h>
  16. #include "lua-compat.h"
  17. #define LUA_CONTEXT "klish_context"
  18. #define LUA_AUTORUN_SW "autostart"
  19. #define LUA_BACKTRACE_SW "backtrace"
  20. #define LUA_PACKAGE_PATH_SW "package.path"
  21. const uint8_t kplugin_lua_major = KPLUGIN_MAJOR;
  22. const uint8_t kplugin_lua_minor = KPLUGIN_MINOR;
  23. struct lua_klish_data {
  24. lua_State *L;
  25. kcontext_t *context;
  26. char *package_path_sw;
  27. char *autorun_path_sw;
  28. int backtrace_sw; // show traceback
  29. };
  30. static lua_State *globalL = NULL;
  31. static int luaB_par(lua_State *L);
  32. static const luaL_Reg klish_lib[] = {
  33. { "par", luaB_par },
  34. { NULL, NULL }
  35. };
  36. #if LUA_VERSION_NUM >= 502
  37. static int traceback (lua_State *L)
  38. {
  39. const char *msg = lua_tostring(L, 1);
  40. if (msg)
  41. luaL_traceback(L, L, msg, 1);
  42. else if (!lua_isnoneornil(L, 1)) { // is there an error object?
  43. if (!luaL_callmeta(L, 1, "__tostring")) // try its 'tostring' metamethod
  44. lua_pushliteral(L, "(no error message)");
  45. }
  46. return 1;
  47. }
  48. #else
  49. static int traceback (lua_State *L)
  50. {
  51. lua_getfield(L, LUA_GLOBALSINDEX, "debug");
  52. if (!lua_istable(L, -1)) {
  53. lua_pop(L, 1);
  54. return 1;
  55. }
  56. lua_getfield(L, -1, "traceback");
  57. if (!lua_isfunction(L, -1)) {
  58. lua_pop(L, 2);
  59. return 1;
  60. }
  61. lua_pushvalue(L, 1); // pass error message
  62. lua_pushinteger(L, 2); // skip this function and traceback
  63. lua_call(L, 2, 1); // call debug.traceback
  64. return 1;
  65. }
  66. #endif
  67. static int report (lua_State *L, int status)
  68. {
  69. if (status && !lua_isnil(L, -1)) {
  70. const char *msg = lua_tostring(L, -1);
  71. if (msg == NULL)
  72. msg = "(error object is not a string)";
  73. fprintf(stderr,"Error: %s\n", msg);
  74. lua_pop(L, 1);
  75. status = -1;
  76. }
  77. return status;
  78. }
  79. static int docall(struct lua_klish_data *ctx, int narg)
  80. {
  81. int status = 0;
  82. int base = 0;
  83. if (ctx->backtrace_sw) {
  84. base = lua_gettop(ctx->L) - narg; // function index
  85. lua_pushcfunction(ctx->L, traceback); // push traceback function
  86. lua_insert(ctx->L, base); // put it under chunk and args
  87. }
  88. status = lua_pcall(ctx->L, narg, LUA_MULTRET, base);
  89. if (ctx->backtrace_sw)
  90. lua_remove(ctx->L, base); // remove traceback function
  91. // force a complete garbage collection in case of errors
  92. if (status != 0)
  93. lua_gc(ctx->L, LUA_GCCOLLECT, 0);
  94. return status;
  95. }
  96. static int clear(lua_State *L)
  97. {
  98. int N = lua_gettop(L);
  99. lua_pop(L, N);
  100. return 0;
  101. }
  102. static int loadscript(struct lua_klish_data *ctx, const char *path)
  103. {
  104. int status = 0;
  105. status = luaL_loadfile(ctx->L, path);
  106. if (!status) {
  107. status = docall(ctx, 0);
  108. }
  109. status = report(ctx->L, status);
  110. clear(ctx->L);
  111. return status;
  112. }
  113. static int dostring(struct lua_klish_data *ctx, const char *s)
  114. {
  115. int status = luaL_loadstring(ctx->L, s) || docall(ctx, 0);
  116. return report(ctx->L, status);
  117. }
  118. static struct lua_klish_data *lua_context(lua_State *L)
  119. {
  120. struct lua_klish_data *ctx;
  121. lua_getglobal(L, LUA_CONTEXT);
  122. ctx = lua_touserdata(L, -1);
  123. lua_pop(L, 1);
  124. return ctx;
  125. }
  126. static int luaB_par(lua_State *L)
  127. {
  128. unsigned int k = 0;
  129. kcontext_t *context;
  130. kpargv_t *pars;
  131. kpargv_pargs_node_t *par_i;
  132. kparg_t *p = NULL;
  133. struct lua_klish_data *ctx;
  134. const char *name = luaL_optstring(L, 1, NULL);
  135. if (!name)
  136. lua_newtable(L);
  137. ctx = lua_context(L);
  138. assert(ctx);
  139. context = ctx->context;
  140. assert(context);
  141. pars = kcontext_pargv(context);
  142. if (!pars)
  143. return (name == NULL);
  144. par_i = kpargv_pargs_iter(pars);
  145. if (kpargv_pargs_len(pars) > 0) {
  146. while ((p = kpargv_pargs_each(&par_i))) {
  147. const char *n = kentry_name(kparg_entry(p));
  148. if (!name) {
  149. lua_pushnumber(L, ++ k);
  150. lua_pushstring(L, n);
  151. lua_rawset(L, -3);
  152. lua_pushstring(L, n);
  153. lua_pushstring(L, kparg_value(p));
  154. lua_rawset(L, -3);
  155. } else if (!strcmp(n, name)) {
  156. lua_pushstring(L, kparg_value(p));
  157. return 1;
  158. }
  159. }
  160. }
  161. return (name == NULL);
  162. }
  163. static int luaopen_klish(lua_State *L)
  164. {
  165. luaL_newlib(L, klish_lib);
  166. return 1;
  167. }
  168. static int clish_env(lua_State *L)
  169. {
  170. luaL_requiref(L, "klish", luaopen_klish, 1);
  171. return 0;
  172. }
  173. static int package_path(struct lua_klish_data *ctx)
  174. {
  175. int rc = 0;
  176. char *str = NULL;
  177. char *path = ctx->package_path_sw;
  178. faux_str_cat(&str, "package.path=\"");
  179. faux_str_cat(&str, path);
  180. faux_str_cat(&str, "\"");
  181. rc = dostring(ctx, str);
  182. clear(ctx->L);
  183. faux_str_free(str);
  184. return rc;
  185. }
  186. static void lstop(lua_State *L, lua_Debug *ar)
  187. {
  188. lua_sethook(L, NULL, 0, 0);
  189. // luaL_error(L, "interrupted!");
  190. ar = ar; // Unused arg
  191. }
  192. static void laction (int i) {
  193. if (!globalL)
  194. return;
  195. lua_sethook(globalL, lstop, LUA_MASKCALL | LUA_MASKRET | LUA_MASKCOUNT, 1);
  196. globalL = NULL; // run only once
  197. }
  198. static void locale_set()
  199. {
  200. setlocale(LC_NUMERIC, "C"); // to avoid . -> , in numbers
  201. setlocale(LC_CTYPE, "C"); // to avoid lower/upper problems
  202. }
  203. static void locale_reset()
  204. {
  205. setlocale(LC_NUMERIC, "");
  206. setlocale(LC_CTYPE, "");
  207. }
  208. static lua_State *lua_init(struct lua_klish_data *ctx)
  209. {
  210. lua_State *L = NULL;
  211. locale_set();
  212. #if LUA_VERSION_NUM >= 502
  213. L = luaL_newstate();
  214. #else
  215. L = lua_open();
  216. #endif
  217. if (!L) {
  218. fprintf(stderr, "Error: Failed to instantiate Lua interpreter\n");
  219. locale_reset();
  220. return NULL;
  221. }
  222. ctx->L = L; // lua state
  223. luaL_openlibs(L);
  224. if (ctx->package_path_sw && package_path(ctx)) {
  225. fprintf(stderr, "Error: Failed to define package env.\n");
  226. goto err;
  227. }
  228. if (clish_env(L)) {
  229. fprintf(stderr, "Error: Failed to define Lua clish env.\n");
  230. goto err;
  231. }
  232. if (ctx->autorun_path_sw) {
  233. if (loadscript(ctx, ctx->autorun_path_sw)) {
  234. goto err;
  235. }
  236. }
  237. globalL = L;
  238. locale_reset();
  239. return L;
  240. err:
  241. lua_close(L);
  242. locale_reset();
  243. return NULL;
  244. }
  245. static int exec_action(struct lua_klish_data *ctx, const char *script)
  246. {
  247. int rc = 0;
  248. lua_State *L = ctx->L;
  249. assert(L);
  250. globalL = L;
  251. lua_pushlightuserdata(L, ctx);
  252. lua_setglobal(L, LUA_CONTEXT);
  253. locale_set();
  254. rc = dostring(ctx, script);
  255. locale_reset();
  256. fflush(stdout);
  257. fflush(stderr);
  258. clear(L);
  259. return rc;
  260. }
  261. int klish_plugin_lua_action(kcontext_t *context)
  262. {
  263. int status = -1;
  264. const char *script = NULL;
  265. struct sigaction sig_old_int;
  266. struct sigaction sig_old_quit;
  267. struct sigaction sig_new;
  268. sigset_t sig_set;
  269. const kplugin_t *plugin;
  270. struct lua_klish_data *ctx;
  271. assert(context);
  272. plugin = kcontext_plugin(context);
  273. assert(plugin);
  274. ctx = kplugin_udata(plugin);
  275. assert(ctx);
  276. script = kcontext_script(context);
  277. if (!script) // Nothing to do
  278. return 0;
  279. sigemptyset(&sig_set);
  280. sig_new.sa_flags = 0;
  281. sig_new.sa_mask = sig_set;
  282. sig_new.sa_handler = laction;
  283. sigaction(SIGINT, &sig_new, &sig_old_int);
  284. sigaction(SIGQUIT, &sig_new, &sig_old_quit);
  285. status = exec_action(ctx, script);
  286. while ( wait(NULL) >= 0 || errno != ECHILD);
  287. // Restore SIGINT and SIGQUIT
  288. sigaction(SIGINT, &sig_old_int, NULL);
  289. sigaction(SIGQUIT, &sig_old_quit, NULL);
  290. err:
  291. return status;
  292. }
  293. static void free_ctx(struct lua_klish_data *ctx)
  294. {
  295. if (ctx->package_path_sw)
  296. faux_str_free(ctx->package_path_sw);
  297. if (ctx->autorun_path_sw)
  298. faux_str_free(ctx->autorun_path_sw);
  299. free(ctx);
  300. }
  301. int kplugin_lua_init(kcontext_t *context)
  302. {
  303. faux_ini_t *ini = NULL;
  304. kplugin_t *plugin = NULL;
  305. const char *p = NULL;
  306. struct lua_klish_data *ctx = NULL;
  307. const char *conf = NULL;
  308. assert(context);
  309. plugin = kcontext_plugin(context);
  310. assert(plugin);
  311. ctx = malloc(sizeof(*ctx));
  312. if (!ctx)
  313. return -1;
  314. conf = kplugin_conf(plugin);
  315. ctx->context = context;
  316. ctx->backtrace_sw = 1;
  317. ctx->package_path_sw = NULL;
  318. ctx->autorun_path_sw = NULL;
  319. ctx->L = NULL;
  320. if (conf) {
  321. ini = faux_ini_new();
  322. faux_ini_parse_str(ini, conf);
  323. p = faux_ini_find(ini, LUA_BACKTRACE_SW);
  324. ctx->backtrace_sw = p ? atoi(p) : 1;
  325. p = faux_ini_find(ini, LUA_PACKAGE_PATH_SW);
  326. ctx->package_path_sw = p ? faux_str_dup(p): NULL;
  327. p = faux_ini_find(ini, LUA_AUTORUN_SW);
  328. ctx->autorun_path_sw = p ? faux_str_dup(p): NULL;
  329. faux_ini_free(ini);
  330. }
  331. kplugin_set_udata(plugin, ctx);
  332. if (!lua_init(ctx)) {
  333. free_ctx(ctx);
  334. return -1;
  335. }
  336. kplugin_add_syms(plugin, ksym_new("lua", klish_plugin_lua_action));
  337. return 0;
  338. }
  339. int kplugin_lua_fini(kcontext_t *context)
  340. {
  341. kplugin_t *plugin = NULL;
  342. lua_State *L = NULL;
  343. struct lua_klish_data *ctx = NULL;
  344. assert(context);
  345. plugin = kcontext_plugin(context);
  346. assert(plugin);
  347. ctx = kplugin_udata(plugin);
  348. if (!ctx)
  349. return 0;
  350. if (ctx->L)
  351. lua_close(ctx->L);
  352. free_ctx(ctx);
  353. return 0;
  354. }