klish_lua.c 7.7 KB

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