1 /*- 2 * Copyright (c) 2011 Wojciech A. Koszek <wkoszek@FreeBSD.org> 3 * Copyright (c) 2014 Pedro Souza <pedrosouza@freebsd.org> 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28 #include <stand.h> 29 #include "bootstrap.h" 30 31 #define lua_c 32 33 #include "lstd.h" 34 35 #include <lua.h> 36 #include <ldebug.h> 37 #include <lauxlib.h> 38 #include <lualib.h> 39 40 #include <lerrno.h> 41 #include <lfs.h> 42 #include <lutils.h> 43 44 struct interp_lua_softc { 45 lua_State *luap; 46 }; 47 48 static struct interp_lua_softc lua_softc; 49 50 #ifdef LUA_DEBUG 51 #define LDBG(...) do { \ 52 printf("%s(%d): ", __func__, __LINE__); \ 53 printf(__VA_ARGS__); \ 54 printf("\n"); \ 55 } while (0) 56 #else 57 #define LDBG(...) 58 #endif 59 60 #define LOADER_LUA LUA_PATH "/loader.lua" 61 62 INTERP_DEFINE("lua"); 63 64 static void * 65 interp_lua_realloc(void *ud __unused, void *ptr, size_t osize __unused, size_t nsize) 66 { 67 68 if (nsize == 0) { 69 free(ptr); 70 return NULL; 71 } 72 return realloc(ptr, nsize); 73 } 74 75 /* 76 * The libraries commented out below either lack the proper 77 * support from libsa, or they are unlikely to be useful 78 * in the bootloader, so have been commented out. 79 */ 80 static const luaL_Reg loadedlibs[] = { 81 {"_G", luaopen_base}, 82 {LUA_LOADLIBNAME, luaopen_package}, 83 // {LUA_COLIBNAME, luaopen_coroutine}, 84 // {LUA_TABLIBNAME, luaopen_table}, 85 {LUA_STRLIBNAME, luaopen_string}, 86 // {LUA_IOLIBNAME, luaopen_io}, 87 // {LUA_OSLIBNAME, luaopen_os}, 88 // {LUA_MATHLIBNAME, luaopen_math}, 89 // {LUA_UTF8LIBNAME, luaopen_utf8}, 90 // {LUA_DBLIBNAME, luaopen_debug}, 91 {"errno", luaopen_errno}, 92 {"io", luaopen_io}, 93 {"lfs", luaopen_lfs}, 94 {"loader", luaopen_loader}, 95 {"pager", luaopen_pager}, 96 {NULL, NULL} 97 }; 98 99 static bool preinit_done = false; 100 101 void 102 interp_preinit(void) 103 { 104 lua_State *luap; 105 struct interp_lua_softc *softc = &lua_softc; 106 const luaL_Reg *lib; 107 lua_init_md_t **fnpp; 108 109 TSENTER(); 110 111 if (preinit_done) 112 return; 113 114 setenv("script.lang", "lua", 1); 115 LDBG("creating context"); 116 117 luap = lua_newstate(interp_lua_realloc, NULL); 118 if (luap == NULL) { 119 printf("problem initializing the Lua interpreter\n"); 120 abort(); 121 } 122 softc->luap = luap; 123 124 /* "require" functions from 'loadedlibs' and set results to global table */ 125 for (lib = loadedlibs; lib->func; lib++) { 126 luaL_requiref(luap, lib->name, lib->func, 1); 127 lua_pop(luap, 1); /* remove lib */ 128 } 129 130 LUA_FOREACH_SET(fnpp) 131 (*fnpp)(luap); 132 133 preinit_done = true; 134 135 TSEXIT(); 136 } 137 138 void 139 interp_init(void) 140 { 141 lua_State *luap; 142 struct interp_lua_softc *softc = &lua_softc; 143 const char *filename; 144 145 TSENTER(); 146 147 luap = softc->luap; 148 filename = getenv("loader_lua"); 149 if (filename == NULL) 150 filename = LOADER_LUA; 151 if (interp_include(filename) != 0) { 152 const char *errstr = lua_tostring(luap, -1); 153 errstr = errstr == NULL ? "unknown" : errstr; 154 printf("ERROR: %s.\n", errstr); 155 lua_pop(luap, 1); 156 setenv("autoboot_delay", "NO", 1); 157 } 158 159 TSEXIT(); 160 } 161 162 int 163 interp_run(const char *line) 164 { 165 int argc, nargc; 166 char **argv; 167 lua_State *luap; 168 struct interp_lua_softc *softc = &lua_softc; 169 int status, ret; 170 171 TSENTER(); 172 luap = softc->luap; 173 LDBG("executing line..."); 174 if ((status = luaL_dostring(luap, line)) != 0) { 175 lua_pop(luap, 1); 176 /* 177 * The line wasn't executable as lua; run it through parse to 178 * to get consistent parsing of command line arguments, then 179 * run it through cli_execute. If that fails, then we'll try it 180 * as a builtin. 181 */ 182 command_errmsg = NULL; 183 if (parse(&argc, &argv, line) == 0) { 184 lua_getglobal(luap, "cli_execute"); 185 for (nargc = 0; nargc < argc; ++nargc) { 186 lua_pushstring(luap, argv[nargc]); 187 } 188 status = lua_pcall(luap, argc, 1, 0); 189 ret = lua_tointeger(luap, 1); 190 lua_pop(luap, 1); 191 if (status != 0 || ret != 0) { 192 /* 193 * Lua cli_execute will pass the function back 194 * through loader.command, which is a proxy to 195 * interp_builtin_cmd. If we failed to interpret 196 * the command, though, then there's a chance 197 * that didn't happen. Call interp_builtin_cmd 198 * directly if our lua_pcall was not successful. 199 */ 200 status = interp_builtin_cmd(argc, argv); 201 } 202 if (status != 0) { 203 if (command_errmsg != NULL) 204 printf("%s\n", command_errmsg); 205 else 206 printf("Command failed\n"); 207 status = CMD_ERROR; 208 } 209 free(argv); 210 } else { 211 printf("Failed to parse \'%s\'\n", line); 212 status = CMD_ERROR; 213 } 214 } 215 216 TSEXIT(); 217 return (status == 0 ? CMD_OK : CMD_ERROR); 218 } 219 220 int 221 interp_include(const char *filename) 222 { 223 struct interp_lua_softc *softc = &lua_softc; 224 225 LDBG("loading file %s", filename); 226 227 return (luaL_dofile(softc->luap, filename)); 228 } 229