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 __FBSDID("$FreeBSD$"); 307cafeaa1SWarner Losh 317cafeaa1SWarner Losh #include <stand.h> 327cafeaa1SWarner Losh #include "bootstrap.h" 337cafeaa1SWarner Losh 347cafeaa1SWarner Losh #define lua_c 357cafeaa1SWarner Losh 367cafeaa1SWarner Losh #include "lstd.h" 377cafeaa1SWarner Losh 387cafeaa1SWarner Losh #include <lua.h> 397cafeaa1SWarner Losh #include <ldebug.h> 407cafeaa1SWarner Losh #include <lauxlib.h> 417cafeaa1SWarner Losh #include <lualib.h> 42f91f3926SConrad Meyer 43f91f3926SConrad Meyer #include <lerrno.h> 4477d4be50SConrad Meyer #include <lfs.h> 45f91f3926SConrad Meyer #include <lutils.h> 467cafeaa1SWarner Losh 477cafeaa1SWarner Losh struct interp_lua_softc { 487cafeaa1SWarner Losh lua_State *luap; 497cafeaa1SWarner Losh }; 507cafeaa1SWarner Losh 517cafeaa1SWarner Losh static struct interp_lua_softc lua_softc; 527cafeaa1SWarner Losh 537cafeaa1SWarner Losh #ifdef LUA_DEBUG 547cafeaa1SWarner Losh #define LDBG(...) do { \ 557cafeaa1SWarner Losh printf("%s(%d): ", __func__, __LINE__); \ 567cafeaa1SWarner Losh printf(__VA_ARGS__); \ 577cafeaa1SWarner Losh printf("\n"); \ 587cafeaa1SWarner Losh } while (0) 597cafeaa1SWarner Losh #else 607cafeaa1SWarner Losh #define LDBG(...) 617cafeaa1SWarner Losh #endif 627cafeaa1SWarner Losh 63ee74c236SKyle Evans #define LOADER_LUA LUA_PATH "/loader.lua" 64ee74c236SKyle Evans 65d3d381b2SKyle Evans INTERP_DEFINE("lua"); 667cafeaa1SWarner Losh 677cafeaa1SWarner Losh static void * 687cafeaa1SWarner Losh interp_lua_realloc(void *ud __unused, void *ptr, size_t osize __unused, size_t nsize) 697cafeaa1SWarner Losh { 707cafeaa1SWarner Losh 717cafeaa1SWarner Losh if (nsize == 0) { 727cafeaa1SWarner Losh free(ptr); 737cafeaa1SWarner Losh return NULL; 747cafeaa1SWarner Losh } 757cafeaa1SWarner Losh return realloc(ptr, nsize); 767cafeaa1SWarner Losh } 777cafeaa1SWarner Losh 787cafeaa1SWarner Losh /* 797cafeaa1SWarner Losh * The libraries commented out below either lack the proper 807cafeaa1SWarner Losh * support from libsa, or they are unlikely to be useful 817cafeaa1SWarner Losh * in the bootloader, so have been commented out. 827cafeaa1SWarner Losh */ 837cafeaa1SWarner Losh static const luaL_Reg loadedlibs[] = { 847cafeaa1SWarner Losh {"_G", luaopen_base}, 857cafeaa1SWarner Losh {LUA_LOADLIBNAME, luaopen_package}, 867cafeaa1SWarner Losh // {LUA_COLIBNAME, luaopen_coroutine}, 877cafeaa1SWarner Losh // {LUA_TABLIBNAME, luaopen_table}, 887cafeaa1SWarner Losh {LUA_STRLIBNAME, luaopen_string}, 897cafeaa1SWarner Losh // {LUA_IOLIBNAME, luaopen_io}, 907cafeaa1SWarner Losh // {LUA_OSLIBNAME, luaopen_os}, 917cafeaa1SWarner Losh // {LUA_MATHLIBNAME, luaopen_math}, 927cafeaa1SWarner Losh // {LUA_UTF8LIBNAME, luaopen_utf8}, 937cafeaa1SWarner Losh // {LUA_DBLIBNAME, luaopen_debug}, 94f91f3926SConrad Meyer {"errno", luaopen_errno}, 956771d4a8SConrad Meyer {"io", luaopen_io}, 9677d4be50SConrad Meyer {"lfs", luaopen_lfs}, 976771d4a8SConrad Meyer {"loader", luaopen_loader}, 987cafeaa1SWarner Losh {NULL, NULL} 997cafeaa1SWarner Losh }; 1007cafeaa1SWarner Losh 1017cafeaa1SWarner Losh void 1027cafeaa1SWarner Losh interp_init(void) 1037cafeaa1SWarner Losh { 1047cafeaa1SWarner Losh lua_State *luap; 1057cafeaa1SWarner Losh struct interp_lua_softc *softc = &lua_softc; 1067cafeaa1SWarner Losh const char *filename; 1077cafeaa1SWarner Losh const luaL_Reg *lib; 1087cafeaa1SWarner Losh 1097cafeaa1SWarner Losh setenv("script.lang", "lua", 1); 1107cafeaa1SWarner Losh LDBG("creating context"); 1117cafeaa1SWarner Losh 1127cafeaa1SWarner Losh luap = lua_newstate(interp_lua_realloc, NULL); 1137cafeaa1SWarner Losh if (luap == NULL) { 1147cafeaa1SWarner Losh printf("problem initializing the Lua interpreter\n"); 1157cafeaa1SWarner Losh abort(); 1167cafeaa1SWarner Losh } 1177cafeaa1SWarner Losh softc->luap = luap; 1187cafeaa1SWarner Losh 1197cafeaa1SWarner Losh /* "require" functions from 'loadedlibs' and set results to global table */ 1207cafeaa1SWarner Losh for (lib = loadedlibs; lib->func; lib++) { 1217cafeaa1SWarner Losh luaL_requiref(luap, lib->name, lib->func, 1); 1227cafeaa1SWarner Losh lua_pop(luap, 1); /* remove lib */ 1237cafeaa1SWarner Losh } 1247cafeaa1SWarner Losh 125ee74c236SKyle Evans filename = LOADER_LUA; 1267cafeaa1SWarner Losh if (interp_include(filename) != 0) { 1277cafeaa1SWarner Losh const char *errstr = lua_tostring(luap, -1); 1287cafeaa1SWarner Losh errstr = errstr == NULL ? "unknown" : errstr; 129bef6cd49SKyle Evans printf("Startup error in %s:\nLUA ERROR: %s.\n", filename, errstr); 1307cafeaa1SWarner Losh lua_pop(luap, 1); 131*17f0dc77SKyle Evans setenv("autoboot_delay", "NO", 1); 1327cafeaa1SWarner Losh } 1337cafeaa1SWarner Losh } 1347cafeaa1SWarner Losh 1357cafeaa1SWarner Losh int 1367cafeaa1SWarner Losh interp_run(const char *line) 1377cafeaa1SWarner Losh { 138afad05b2SKyle Evans int argc, nargc; 1397cafeaa1SWarner Losh char **argv; 1407cafeaa1SWarner Losh lua_State *luap; 1417cafeaa1SWarner Losh struct interp_lua_softc *softc = &lua_softc; 1422ac6dfb0SKyle Evans int status, ret; 1437cafeaa1SWarner Losh 1447cafeaa1SWarner Losh luap = softc->luap; 1457cafeaa1SWarner Losh LDBG("executing line..."); 1467cafeaa1SWarner Losh if ((status = luaL_dostring(luap, line)) != 0) { 1477cafeaa1SWarner Losh lua_pop(luap, 1); 148afad05b2SKyle Evans /* 149afad05b2SKyle Evans * The line wasn't executable as lua; run it through parse to 150afad05b2SKyle Evans * to get consistent parsing of command line arguments, then 151afad05b2SKyle Evans * run it through cli_execute. If that fails, then we'll try it 152afad05b2SKyle Evans * as a builtin. 153afad05b2SKyle Evans */ 1542ac6dfb0SKyle Evans command_errmsg = NULL; 1557cafeaa1SWarner Losh if (parse(&argc, &argv, line) == 0) { 156afad05b2SKyle Evans lua_getglobal(luap, "cli_execute"); 157afad05b2SKyle Evans for (nargc = 0; nargc < argc; ++nargc) { 158afad05b2SKyle Evans lua_pushstring(luap, argv[nargc]); 159afad05b2SKyle Evans } 160afad05b2SKyle Evans status = lua_pcall(luap, argc, 1, 0); 1612ac6dfb0SKyle Evans ret = lua_tointeger(luap, 1); 162afad05b2SKyle Evans lua_pop(luap, 1); 1632ac6dfb0SKyle Evans if (status != 0 || ret != 0) { 164afad05b2SKyle Evans /* 165afad05b2SKyle Evans * Lua cli_execute will pass the function back 166afad05b2SKyle Evans * through loader.command, which is a proxy to 167afad05b2SKyle Evans * interp_builtin_cmd. If we failed to interpret 168afad05b2SKyle Evans * the command, though, then there's a chance 169afad05b2SKyle Evans * that didn't happen. Call interp_builtin_cmd 170afad05b2SKyle Evans * directly if our lua_pcall was not successful. 171afad05b2SKyle Evans */ 1727cafeaa1SWarner Losh status = interp_builtin_cmd(argc, argv); 173afad05b2SKyle Evans } 174afad05b2SKyle Evans if (status != 0) { 1752ac6dfb0SKyle Evans if (command_errmsg != NULL) 1762ac6dfb0SKyle Evans printf("%s\n", command_errmsg); 1772ac6dfb0SKyle Evans else 1787cafeaa1SWarner Losh printf("Command failed\n"); 179afad05b2SKyle Evans status = CMD_ERROR; 180afad05b2SKyle Evans } 1817cafeaa1SWarner Losh free(argv); 1827cafeaa1SWarner Losh } else { 1837cafeaa1SWarner Losh printf("Failed to parse \'%s\'\n", line); 184afad05b2SKyle Evans status = CMD_ERROR; 1857cafeaa1SWarner Losh } 1867cafeaa1SWarner Losh } 1877cafeaa1SWarner Losh 1887cafeaa1SWarner Losh return (status == 0 ? CMD_OK : CMD_ERROR); 1897cafeaa1SWarner Losh } 1907cafeaa1SWarner Losh 1917cafeaa1SWarner Losh int 1927cafeaa1SWarner Losh interp_include(const char *filename) 1937cafeaa1SWarner Losh { 1947cafeaa1SWarner Losh struct interp_lua_softc *softc = &lua_softc; 1957cafeaa1SWarner Losh 1967cafeaa1SWarner Losh LDBG("loading file %s", filename); 1977cafeaa1SWarner Losh 1987cafeaa1SWarner Losh return (luaL_dofile(softc->luap, filename)); 1997cafeaa1SWarner Losh } 200