klish_lua.c 7.7 KB

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