klish_lua.c 10 KB

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