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 637cafeaa1SWarner Losh 647cafeaa1SWarner Losh static void * 657cafeaa1SWarner Losh interp_lua_realloc(void *ud __unused, void *ptr, size_t osize __unused, size_t nsize) 667cafeaa1SWarner Losh { 677cafeaa1SWarner Losh 687cafeaa1SWarner Losh if (nsize == 0) { 697cafeaa1SWarner Losh free(ptr); 707cafeaa1SWarner Losh return NULL; 717cafeaa1SWarner Losh } 727cafeaa1SWarner Losh return realloc(ptr, nsize); 737cafeaa1SWarner Losh } 747cafeaa1SWarner Losh 757cafeaa1SWarner Losh /* 767cafeaa1SWarner Losh * The libraries commented out below either lack the proper 777cafeaa1SWarner Losh * support from libsa, or they are unlikely to be useful 787cafeaa1SWarner Losh * in the bootloader, so have been commented out. 797cafeaa1SWarner Losh */ 807cafeaa1SWarner Losh static const luaL_Reg loadedlibs[] = { 817cafeaa1SWarner Losh {"_G", luaopen_base}, 827cafeaa1SWarner Losh {LUA_LOADLIBNAME, luaopen_package}, 837cafeaa1SWarner Losh // {LUA_COLIBNAME, luaopen_coroutine}, 847cafeaa1SWarner Losh // {LUA_TABLIBNAME, luaopen_table}, 857cafeaa1SWarner Losh {LUA_STRLIBNAME, luaopen_string}, 867cafeaa1SWarner Losh // {LUA_IOLIBNAME, luaopen_io}, 877cafeaa1SWarner Losh // {LUA_OSLIBNAME, luaopen_os}, 887cafeaa1SWarner Losh // {LUA_MATHLIBNAME, luaopen_math}, 897cafeaa1SWarner Losh // {LUA_UTF8LIBNAME, luaopen_utf8}, 907cafeaa1SWarner Losh // {LUA_DBLIBNAME, luaopen_debug}, 91f91f3926SConrad Meyer {"errno", luaopen_errno}, 926771d4a8SConrad Meyer {"io", luaopen_io}, 9377d4be50SConrad Meyer {"lfs", luaopen_lfs}, 946771d4a8SConrad Meyer {"loader", luaopen_loader}, 957cafeaa1SWarner Losh {NULL, NULL} 967cafeaa1SWarner Losh }; 977cafeaa1SWarner Losh 987cafeaa1SWarner Losh void 997cafeaa1SWarner Losh interp_init(void) 1007cafeaa1SWarner Losh { 1017cafeaa1SWarner Losh lua_State *luap; 1027cafeaa1SWarner Losh struct interp_lua_softc *softc = &lua_softc; 1037cafeaa1SWarner Losh const char *filename; 1047cafeaa1SWarner Losh const luaL_Reg *lib; 1057cafeaa1SWarner Losh 1067cafeaa1SWarner Losh setenv("script.lang", "lua", 1); 1077cafeaa1SWarner Losh LDBG("creating context"); 1087cafeaa1SWarner Losh 1097cafeaa1SWarner Losh luap = lua_newstate(interp_lua_realloc, NULL); 1107cafeaa1SWarner Losh if (luap == NULL) { 1117cafeaa1SWarner Losh printf("problem initializing the Lua interpreter\n"); 1127cafeaa1SWarner Losh abort(); 1137cafeaa1SWarner Losh } 1147cafeaa1SWarner Losh softc->luap = luap; 1157cafeaa1SWarner Losh 1167cafeaa1SWarner Losh /* "require" functions from 'loadedlibs' and set results to global table */ 1177cafeaa1SWarner Losh for (lib = loadedlibs; lib->func; lib++) { 1187cafeaa1SWarner Losh luaL_requiref(luap, lib->name, lib->func, 1); 1197cafeaa1SWarner Losh lua_pop(luap, 1); /* remove lib */ 1207cafeaa1SWarner Losh } 1217cafeaa1SWarner Losh 1227cafeaa1SWarner Losh filename = "/boot/lua/loader.lua"; 1237cafeaa1SWarner Losh if (interp_include(filename) != 0) { 1247cafeaa1SWarner Losh const char *errstr = lua_tostring(luap, -1); 1257cafeaa1SWarner Losh errstr = errstr == NULL ? "unknown" : errstr; 126bef6cd49SKyle Evans printf("Startup error in %s:\nLUA ERROR: %s.\n", filename, errstr); 1277cafeaa1SWarner Losh lua_pop(luap, 1); 1287cafeaa1SWarner Losh } 1297cafeaa1SWarner Losh } 1307cafeaa1SWarner Losh 1317cafeaa1SWarner Losh int 1327cafeaa1SWarner Losh interp_run(const char *line) 1337cafeaa1SWarner Losh { 134afad05b2SKyle Evans int argc, nargc; 1357cafeaa1SWarner Losh char **argv; 1367cafeaa1SWarner Losh lua_State *luap; 1377cafeaa1SWarner Losh struct interp_lua_softc *softc = &lua_softc; 138*2ac6dfb0SKyle Evans int status, ret; 1397cafeaa1SWarner Losh 1407cafeaa1SWarner Losh luap = softc->luap; 1417cafeaa1SWarner Losh LDBG("executing line..."); 1427cafeaa1SWarner Losh if ((status = luaL_dostring(luap, line)) != 0) { 1437cafeaa1SWarner Losh lua_pop(luap, 1); 144afad05b2SKyle Evans /* 145afad05b2SKyle Evans * The line wasn't executable as lua; run it through parse to 146afad05b2SKyle Evans * to get consistent parsing of command line arguments, then 147afad05b2SKyle Evans * run it through cli_execute. If that fails, then we'll try it 148afad05b2SKyle Evans * as a builtin. 149afad05b2SKyle Evans */ 150*2ac6dfb0SKyle Evans command_errmsg = NULL; 1517cafeaa1SWarner Losh if (parse(&argc, &argv, line) == 0) { 152afad05b2SKyle Evans lua_getglobal(luap, "cli_execute"); 153afad05b2SKyle Evans for (nargc = 0; nargc < argc; ++nargc) { 154afad05b2SKyle Evans lua_pushstring(luap, argv[nargc]); 155afad05b2SKyle Evans } 156afad05b2SKyle Evans status = lua_pcall(luap, argc, 1, 0); 157*2ac6dfb0SKyle Evans ret = lua_tointeger(luap, 1); 158afad05b2SKyle Evans lua_pop(luap, 1); 159*2ac6dfb0SKyle Evans if (status != 0 || ret != 0) { 160afad05b2SKyle Evans /* 161afad05b2SKyle Evans * Lua cli_execute will pass the function back 162afad05b2SKyle Evans * through loader.command, which is a proxy to 163afad05b2SKyle Evans * interp_builtin_cmd. If we failed to interpret 164afad05b2SKyle Evans * the command, though, then there's a chance 165afad05b2SKyle Evans * that didn't happen. Call interp_builtin_cmd 166afad05b2SKyle Evans * directly if our lua_pcall was not successful. 167afad05b2SKyle Evans */ 1687cafeaa1SWarner Losh status = interp_builtin_cmd(argc, argv); 169afad05b2SKyle Evans } 170afad05b2SKyle Evans if (status != 0) { 171*2ac6dfb0SKyle Evans if (command_errmsg != NULL) 172*2ac6dfb0SKyle Evans printf("%s\n", command_errmsg); 173*2ac6dfb0SKyle Evans else 1747cafeaa1SWarner Losh printf("Command failed\n"); 175afad05b2SKyle Evans status = CMD_ERROR; 176afad05b2SKyle Evans } 1777cafeaa1SWarner Losh free(argv); 1787cafeaa1SWarner Losh } else { 1797cafeaa1SWarner Losh printf("Failed to parse \'%s\'\n", line); 180afad05b2SKyle Evans status = CMD_ERROR; 1817cafeaa1SWarner Losh } 1827cafeaa1SWarner Losh } 1837cafeaa1SWarner Losh 1847cafeaa1SWarner Losh return (status == 0 ? CMD_OK : CMD_ERROR); 1857cafeaa1SWarner Losh } 1867cafeaa1SWarner Losh 1877cafeaa1SWarner Losh int 1887cafeaa1SWarner Losh interp_include(const char *filename) 1897cafeaa1SWarner Losh { 1907cafeaa1SWarner Losh struct interp_lua_softc *softc = &lua_softc; 1917cafeaa1SWarner Losh 1927cafeaa1SWarner Losh LDBG("loading file %s", filename); 1937cafeaa1SWarner Losh 1947cafeaa1SWarner Losh return (luaL_dofile(softc->luap, filename)); 1957cafeaa1SWarner Losh } 196