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 1007cafeaa1SWarner Losh void 1017cafeaa1SWarner Losh interp_init(void) 1027cafeaa1SWarner Losh { 1037cafeaa1SWarner Losh lua_State *luap; 1047cafeaa1SWarner Losh struct interp_lua_softc *softc = &lua_softc; 1057cafeaa1SWarner Losh const char *filename; 1067cafeaa1SWarner Losh const luaL_Reg *lib; 107*0921a771SWarner Losh lua_init_md_t **fnpp; 1087cafeaa1SWarner Losh 109313724baSColin Percival TSENTER(); 110313724baSColin Percival 1117cafeaa1SWarner Losh setenv("script.lang", "lua", 1); 1127cafeaa1SWarner Losh LDBG("creating context"); 1137cafeaa1SWarner Losh 1147cafeaa1SWarner Losh luap = lua_newstate(interp_lua_realloc, NULL); 1157cafeaa1SWarner Losh if (luap == NULL) { 1167cafeaa1SWarner Losh printf("problem initializing the Lua interpreter\n"); 1177cafeaa1SWarner Losh abort(); 1187cafeaa1SWarner Losh } 1197cafeaa1SWarner Losh softc->luap = luap; 1207cafeaa1SWarner Losh 1217cafeaa1SWarner Losh /* "require" functions from 'loadedlibs' and set results to global table */ 1227cafeaa1SWarner Losh for (lib = loadedlibs; lib->func; lib++) { 1237cafeaa1SWarner Losh luaL_requiref(luap, lib->name, lib->func, 1); 1247cafeaa1SWarner Losh lua_pop(luap, 1); /* remove lib */ 1257cafeaa1SWarner Losh } 1267cafeaa1SWarner Losh 127*0921a771SWarner Losh LUA_FOREACH_SET(fnpp) 128*0921a771SWarner Losh (*fnpp)(luap); 1299b162310SWarner Losh 130cd147a2aSWarner Losh filename = getenv("loader_lua"); 131cd147a2aSWarner Losh if (filename == NULL) 132ee74c236SKyle Evans filename = LOADER_LUA; 1337cafeaa1SWarner Losh if (interp_include(filename) != 0) { 1347cafeaa1SWarner Losh const char *errstr = lua_tostring(luap, -1); 1357cafeaa1SWarner Losh errstr = errstr == NULL ? "unknown" : errstr; 13648260b4bSKyle Evans printf("ERROR: %s.\n", errstr); 1377cafeaa1SWarner Losh lua_pop(luap, 1); 13817f0dc77SKyle Evans setenv("autoboot_delay", "NO", 1); 1397cafeaa1SWarner Losh } 140313724baSColin Percival 141313724baSColin Percival TSEXIT(); 1427cafeaa1SWarner Losh } 1437cafeaa1SWarner Losh 1447cafeaa1SWarner Losh int 1457cafeaa1SWarner Losh interp_run(const char *line) 1467cafeaa1SWarner Losh { 147afad05b2SKyle Evans int argc, nargc; 1487cafeaa1SWarner Losh char **argv; 1497cafeaa1SWarner Losh lua_State *luap; 1507cafeaa1SWarner Losh struct interp_lua_softc *softc = &lua_softc; 1512ac6dfb0SKyle Evans int status, ret; 1527cafeaa1SWarner Losh 153313724baSColin Percival TSENTER(); 1547cafeaa1SWarner Losh luap = softc->luap; 1557cafeaa1SWarner Losh LDBG("executing line..."); 1567cafeaa1SWarner Losh if ((status = luaL_dostring(luap, line)) != 0) { 1577cafeaa1SWarner Losh lua_pop(luap, 1); 158afad05b2SKyle Evans /* 159afad05b2SKyle Evans * The line wasn't executable as lua; run it through parse to 160afad05b2SKyle Evans * to get consistent parsing of command line arguments, then 161afad05b2SKyle Evans * run it through cli_execute. If that fails, then we'll try it 162afad05b2SKyle Evans * as a builtin. 163afad05b2SKyle Evans */ 1642ac6dfb0SKyle Evans command_errmsg = NULL; 1657cafeaa1SWarner Losh if (parse(&argc, &argv, line) == 0) { 166afad05b2SKyle Evans lua_getglobal(luap, "cli_execute"); 167afad05b2SKyle Evans for (nargc = 0; nargc < argc; ++nargc) { 168afad05b2SKyle Evans lua_pushstring(luap, argv[nargc]); 169afad05b2SKyle Evans } 170afad05b2SKyle Evans status = lua_pcall(luap, argc, 1, 0); 1712ac6dfb0SKyle Evans ret = lua_tointeger(luap, 1); 172afad05b2SKyle Evans lua_pop(luap, 1); 1732ac6dfb0SKyle Evans if (status != 0 || ret != 0) { 174afad05b2SKyle Evans /* 175afad05b2SKyle Evans * Lua cli_execute will pass the function back 176afad05b2SKyle Evans * through loader.command, which is a proxy to 177afad05b2SKyle Evans * interp_builtin_cmd. If we failed to interpret 178afad05b2SKyle Evans * the command, though, then there's a chance 179afad05b2SKyle Evans * that didn't happen. Call interp_builtin_cmd 180afad05b2SKyle Evans * directly if our lua_pcall was not successful. 181afad05b2SKyle Evans */ 1827cafeaa1SWarner Losh status = interp_builtin_cmd(argc, argv); 183afad05b2SKyle Evans } 184afad05b2SKyle Evans if (status != 0) { 1852ac6dfb0SKyle Evans if (command_errmsg != NULL) 1862ac6dfb0SKyle Evans printf("%s\n", command_errmsg); 1872ac6dfb0SKyle Evans else 1887cafeaa1SWarner Losh printf("Command failed\n"); 189afad05b2SKyle Evans status = CMD_ERROR; 190afad05b2SKyle Evans } 1917cafeaa1SWarner Losh free(argv); 1927cafeaa1SWarner Losh } else { 1937cafeaa1SWarner Losh printf("Failed to parse \'%s\'\n", line); 194afad05b2SKyle Evans status = CMD_ERROR; 1957cafeaa1SWarner Losh } 1967cafeaa1SWarner Losh } 1977cafeaa1SWarner Losh 198313724baSColin Percival TSEXIT(); 1997cafeaa1SWarner Losh return (status == 0 ? CMD_OK : CMD_ERROR); 2007cafeaa1SWarner Losh } 2017cafeaa1SWarner Losh 2027cafeaa1SWarner Losh int 2037cafeaa1SWarner Losh interp_include(const char *filename) 2047cafeaa1SWarner Losh { 2057cafeaa1SWarner Losh struct interp_lua_softc *softc = &lua_softc; 2067cafeaa1SWarner Losh 2077cafeaa1SWarner Losh LDBG("loading file %s", filename); 2087cafeaa1SWarner Losh 2097cafeaa1SWarner Losh return (luaL_dofile(softc->luap, filename)); 2107cafeaa1SWarner Losh } 211