17cafeaa1SWarner Losh /*- 27cafeaa1SWarner Losh * Copyright (c) 2011 Wojciech A. Koszek <wkoszek@FreeBSD.org> 37cafeaa1SWarner Losh * Copyright (c) 2014 Pedro Souza <pedrosouza@freebsd.org> 47cafeaa1SWarner Losh * All rights reserved. 57cafeaa1SWarner Losh * 67cafeaa1SWarner Losh * Redistribution and use in source and binary forms, with or without 77cafeaa1SWarner Losh * modification, are permitted provided that the following conditions 87cafeaa1SWarner Losh * are met: 97cafeaa1SWarner Losh * 1. Redistributions of source code must retain the above copyright 107cafeaa1SWarner Losh * notice, this list of conditions and the following disclaimer. 117cafeaa1SWarner Losh * 2. Redistributions in binary form must reproduce the above copyright 127cafeaa1SWarner Losh * notice, this list of conditions and the following disclaimer in the 137cafeaa1SWarner Losh * documentation and/or other materials provided with the distribution. 147cafeaa1SWarner Losh * 157cafeaa1SWarner Losh * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 167cafeaa1SWarner Losh * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 177cafeaa1SWarner Losh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 187cafeaa1SWarner Losh * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 197cafeaa1SWarner Losh * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 207cafeaa1SWarner Losh * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 217cafeaa1SWarner Losh * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 227cafeaa1SWarner Losh * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 237cafeaa1SWarner Losh * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 247cafeaa1SWarner Losh * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 257cafeaa1SWarner Losh * SUCH DAMAGE. 267cafeaa1SWarner Losh */ 277cafeaa1SWarner Losh 287cafeaa1SWarner Losh #include <sys/cdefs.h> 297cafeaa1SWarner Losh #include <stand.h> 307cafeaa1SWarner Losh #include "bootstrap.h" 317cafeaa1SWarner Losh 327cafeaa1SWarner Losh #define lua_c 337cafeaa1SWarner Losh 347cafeaa1SWarner Losh #include "lstd.h" 357cafeaa1SWarner Losh 367cafeaa1SWarner Losh #include <lua.h> 377cafeaa1SWarner Losh #include <ldebug.h> 387cafeaa1SWarner Losh #include <lauxlib.h> 397cafeaa1SWarner Losh #include <lualib.h> 40f91f3926SConrad Meyer 41f91f3926SConrad Meyer #include <lerrno.h> 4277d4be50SConrad Meyer #include <lfs.h> 43f91f3926SConrad Meyer #include <lutils.h> 447cafeaa1SWarner Losh 457cafeaa1SWarner Losh struct interp_lua_softc { 467cafeaa1SWarner Losh lua_State *luap; 477cafeaa1SWarner Losh }; 487cafeaa1SWarner Losh 497cafeaa1SWarner Losh static struct interp_lua_softc lua_softc; 507cafeaa1SWarner Losh 517cafeaa1SWarner Losh #ifdef LUA_DEBUG 527cafeaa1SWarner Losh #define LDBG(...) do { \ 537cafeaa1SWarner Losh printf("%s(%d): ", __func__, __LINE__); \ 547cafeaa1SWarner Losh printf(__VA_ARGS__); \ 557cafeaa1SWarner Losh printf("\n"); \ 567cafeaa1SWarner Losh } while (0) 577cafeaa1SWarner Losh #else 587cafeaa1SWarner Losh #define LDBG(...) 597cafeaa1SWarner Losh #endif 607cafeaa1SWarner Losh 61ee74c236SKyle Evans #define LOADER_LUA LUA_PATH "/loader.lua" 62ee74c236SKyle Evans 63d3d381b2SKyle Evans INTERP_DEFINE("lua"); 647cafeaa1SWarner Losh 657cafeaa1SWarner Losh static void * 667cafeaa1SWarner Losh interp_lua_realloc(void *ud __unused, void *ptr, size_t osize __unused, size_t nsize) 677cafeaa1SWarner Losh { 687cafeaa1SWarner Losh 697cafeaa1SWarner Losh if (nsize == 0) { 707cafeaa1SWarner Losh free(ptr); 717cafeaa1SWarner Losh return NULL; 727cafeaa1SWarner Losh } 737cafeaa1SWarner Losh return realloc(ptr, nsize); 747cafeaa1SWarner Losh } 757cafeaa1SWarner Losh 767cafeaa1SWarner Losh /* 777cafeaa1SWarner Losh * The libraries commented out below either lack the proper 787cafeaa1SWarner Losh * support from libsa, or they are unlikely to be useful 797cafeaa1SWarner Losh * in the bootloader, so have been commented out. 807cafeaa1SWarner Losh */ 817cafeaa1SWarner Losh static const luaL_Reg loadedlibs[] = { 827cafeaa1SWarner Losh {"_G", luaopen_base}, 837cafeaa1SWarner Losh {LUA_LOADLIBNAME, luaopen_package}, 847cafeaa1SWarner Losh // {LUA_COLIBNAME, luaopen_coroutine}, 857cafeaa1SWarner Losh // {LUA_TABLIBNAME, luaopen_table}, 867cafeaa1SWarner Losh {LUA_STRLIBNAME, luaopen_string}, 877cafeaa1SWarner Losh // {LUA_IOLIBNAME, luaopen_io}, 887cafeaa1SWarner Losh // {LUA_OSLIBNAME, luaopen_os}, 897cafeaa1SWarner Losh // {LUA_MATHLIBNAME, luaopen_math}, 907cafeaa1SWarner Losh // {LUA_UTF8LIBNAME, luaopen_utf8}, 917cafeaa1SWarner Losh // {LUA_DBLIBNAME, luaopen_debug}, 92f91f3926SConrad Meyer {"errno", luaopen_errno}, 936771d4a8SConrad Meyer {"io", luaopen_io}, 9477d4be50SConrad Meyer {"lfs", luaopen_lfs}, 956771d4a8SConrad Meyer {"loader", luaopen_loader}, 960a0d522bSKyle Evans {"pager", luaopen_pager}, 977cafeaa1SWarner Losh {NULL, NULL} 987cafeaa1SWarner Losh }; 997cafeaa1SWarner Losh 100*9b162310SWarner Losh static void 101*9b162310SWarner Losh interp_init_md(lua_State *L) 102*9b162310SWarner Losh { 103*9b162310SWarner Losh luaL_requiref(L, "gfx", luaopen_gfx, 1); 104*9b162310SWarner Losh lua_pop(L, 1); /* Remove lib */ 105*9b162310SWarner Losh 106*9b162310SWarner Losh /* 107*9b162310SWarner Losh * Add in the comparability references in the loader table. Doing it with 108*9b162310SWarner Losh * a pseudo-embedded script is easier than the raw calls. 109*9b162310SWarner Losh */ 110*9b162310SWarner Losh if (luaL_dostring(L, 111*9b162310SWarner Losh "loader.fb_bezier = gfx.fb_bezier\n" 112*9b162310SWarner Losh "loader.fb_drawrect = gfx.fb_drawrect\n" 113*9b162310SWarner Losh "loader.fb_line = gfx.fb_line\n" 114*9b162310SWarner Losh "loader.fb_putimage = gfx.fb_putimage\n" 115*9b162310SWarner Losh "loader.fb_setpixel = gfx.fb_setpixel\n" 116*9b162310SWarner Losh "loader.term_drawrect = gfx.term_drawrect\n" 117*9b162310SWarner Losh "loader.term_putimage = gfx.term_putimage") != 0) { 118*9b162310SWarner Losh lua_pop(L, 1); 119*9b162310SWarner Losh const char *errstr = lua_tostring(L, -1); 120*9b162310SWarner Losh errstr = errstr == NULL ? "unknown" : errstr; 121*9b162310SWarner Losh printf("Error adding compat loader bindings: %s.\n", errstr); 122*9b162310SWarner Losh } 123*9b162310SWarner Losh } 124*9b162310SWarner Losh 1257cafeaa1SWarner Losh void 1267cafeaa1SWarner Losh interp_init(void) 1277cafeaa1SWarner Losh { 1287cafeaa1SWarner Losh lua_State *luap; 1297cafeaa1SWarner Losh struct interp_lua_softc *softc = &lua_softc; 1307cafeaa1SWarner Losh const char *filename; 1317cafeaa1SWarner Losh const luaL_Reg *lib; 1327cafeaa1SWarner Losh 133313724baSColin Percival TSENTER(); 134313724baSColin Percival 1357cafeaa1SWarner Losh setenv("script.lang", "lua", 1); 1367cafeaa1SWarner Losh LDBG("creating context"); 1377cafeaa1SWarner Losh 1387cafeaa1SWarner Losh luap = lua_newstate(interp_lua_realloc, NULL); 1397cafeaa1SWarner Losh if (luap == NULL) { 1407cafeaa1SWarner Losh printf("problem initializing the Lua interpreter\n"); 1417cafeaa1SWarner Losh abort(); 1427cafeaa1SWarner Losh } 1437cafeaa1SWarner Losh softc->luap = luap; 1447cafeaa1SWarner Losh 1457cafeaa1SWarner Losh /* "require" functions from 'loadedlibs' and set results to global table */ 1467cafeaa1SWarner Losh for (lib = loadedlibs; lib->func; lib++) { 1477cafeaa1SWarner Losh luaL_requiref(luap, lib->name, lib->func, 1); 1487cafeaa1SWarner Losh lua_pop(luap, 1); /* remove lib */ 1497cafeaa1SWarner Losh } 1507cafeaa1SWarner Losh 151*9b162310SWarner Losh interp_init_md(luap); 152*9b162310SWarner Losh 153cd147a2aSWarner Losh filename = getenv("loader_lua"); 154cd147a2aSWarner Losh if (filename == NULL) 155ee74c236SKyle Evans filename = LOADER_LUA; 1567cafeaa1SWarner Losh if (interp_include(filename) != 0) { 1577cafeaa1SWarner Losh const char *errstr = lua_tostring(luap, -1); 1587cafeaa1SWarner Losh errstr = errstr == NULL ? "unknown" : errstr; 15948260b4bSKyle Evans printf("ERROR: %s.\n", errstr); 1607cafeaa1SWarner Losh lua_pop(luap, 1); 16117f0dc77SKyle Evans setenv("autoboot_delay", "NO", 1); 1627cafeaa1SWarner Losh } 163313724baSColin Percival 164313724baSColin Percival TSEXIT(); 1657cafeaa1SWarner Losh } 1667cafeaa1SWarner Losh 1677cafeaa1SWarner Losh int 1687cafeaa1SWarner Losh interp_run(const char *line) 1697cafeaa1SWarner Losh { 170afad05b2SKyle Evans int argc, nargc; 1717cafeaa1SWarner Losh char **argv; 1727cafeaa1SWarner Losh lua_State *luap; 1737cafeaa1SWarner Losh struct interp_lua_softc *softc = &lua_softc; 1742ac6dfb0SKyle Evans int status, ret; 1757cafeaa1SWarner Losh 176313724baSColin Percival TSENTER(); 1777cafeaa1SWarner Losh luap = softc->luap; 1787cafeaa1SWarner Losh LDBG("executing line..."); 1797cafeaa1SWarner Losh if ((status = luaL_dostring(luap, line)) != 0) { 1807cafeaa1SWarner Losh lua_pop(luap, 1); 181afad05b2SKyle Evans /* 182afad05b2SKyle Evans * The line wasn't executable as lua; run it through parse to 183afad05b2SKyle Evans * to get consistent parsing of command line arguments, then 184afad05b2SKyle Evans * run it through cli_execute. If that fails, then we'll try it 185afad05b2SKyle Evans * as a builtin. 186afad05b2SKyle Evans */ 1872ac6dfb0SKyle Evans command_errmsg = NULL; 1887cafeaa1SWarner Losh if (parse(&argc, &argv, line) == 0) { 189afad05b2SKyle Evans lua_getglobal(luap, "cli_execute"); 190afad05b2SKyle Evans for (nargc = 0; nargc < argc; ++nargc) { 191afad05b2SKyle Evans lua_pushstring(luap, argv[nargc]); 192afad05b2SKyle Evans } 193afad05b2SKyle Evans status = lua_pcall(luap, argc, 1, 0); 1942ac6dfb0SKyle Evans ret = lua_tointeger(luap, 1); 195afad05b2SKyle Evans lua_pop(luap, 1); 1962ac6dfb0SKyle Evans if (status != 0 || ret != 0) { 197afad05b2SKyle Evans /* 198afad05b2SKyle Evans * Lua cli_execute will pass the function back 199afad05b2SKyle Evans * through loader.command, which is a proxy to 200afad05b2SKyle Evans * interp_builtin_cmd. If we failed to interpret 201afad05b2SKyle Evans * the command, though, then there's a chance 202afad05b2SKyle Evans * that didn't happen. Call interp_builtin_cmd 203afad05b2SKyle Evans * directly if our lua_pcall was not successful. 204afad05b2SKyle Evans */ 2057cafeaa1SWarner Losh status = interp_builtin_cmd(argc, argv); 206afad05b2SKyle Evans } 207afad05b2SKyle Evans if (status != 0) { 2082ac6dfb0SKyle Evans if (command_errmsg != NULL) 2092ac6dfb0SKyle Evans printf("%s\n", command_errmsg); 2102ac6dfb0SKyle Evans else 2117cafeaa1SWarner Losh printf("Command failed\n"); 212afad05b2SKyle Evans status = CMD_ERROR; 213afad05b2SKyle Evans } 2147cafeaa1SWarner Losh free(argv); 2157cafeaa1SWarner Losh } else { 2167cafeaa1SWarner Losh printf("Failed to parse \'%s\'\n", line); 217afad05b2SKyle Evans status = CMD_ERROR; 2187cafeaa1SWarner Losh } 2197cafeaa1SWarner Losh } 2207cafeaa1SWarner Losh 221313724baSColin Percival TSEXIT(); 2227cafeaa1SWarner Losh return (status == 0 ? CMD_OK : CMD_ERROR); 2237cafeaa1SWarner Losh } 2247cafeaa1SWarner Losh 2257cafeaa1SWarner Losh int 2267cafeaa1SWarner Losh interp_include(const char *filename) 2277cafeaa1SWarner Losh { 2287cafeaa1SWarner Losh struct interp_lua_softc *softc = &lua_softc; 2297cafeaa1SWarner Losh 2307cafeaa1SWarner Losh LDBG("loading file %s", filename); 2317cafeaa1SWarner Losh 2327cafeaa1SWarner Losh return (luaL_dofile(softc->luap, filename)); 2337cafeaa1SWarner Losh } 234