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 <sys/cdefs.h> 29 #include <stand.h> 30 #include "bootstrap.h" 31 32 #define lua_c 33 34 #include "lstd.h" 35 36 #include <lua.h> 37 #include <ldebug.h> 38 #include <lauxlib.h> 39 #include <lualib.h> 40 41 #include <lerrno.h> 42 #include <lfs.h> 43 #include <lutils.h> 44 45 struct interp_lua_softc { 46 lua_State *luap; 47 }; 48 49 static struct interp_lua_softc lua_softc; 50 51 #ifdef LUA_DEBUG 52 #define LDBG(...) do { \ 53 printf("%s(%d): ", __func__, __LINE__); \ 54 printf(__VA_ARGS__); \ 55 printf("\n"); \ 56 } while (0) 57 #else 58 #define LDBG(...) 59 #endif 60 61 #define LOADER_LUA LUA_PATH "/loader.lua" 62 63 INTERP_DEFINE("lua"); 64 65 static void * 66 interp_lua_realloc(void *ud __unused, void *ptr, size_t osize __unused, size_t nsize) 67 { 68 69 if (nsize == 0) { 70 free(ptr); 71 return NULL; 72 } 73 return realloc(ptr, nsize); 74 } 75 76 /* 77 * The libraries commented out below either lack the proper 78 * support from libsa, or they are unlikely to be useful 79 * in the bootloader, so have been commented out. 80 */ 81 static const luaL_Reg loadedlibs[] = { 82 {"_G", luaopen_base}, 83 {LUA_LOADLIBNAME, luaopen_package}, 84 // {LUA_COLIBNAME, luaopen_coroutine}, 85 // {LUA_TABLIBNAME, luaopen_table}, 86 {LUA_STRLIBNAME, luaopen_string}, 87 // {LUA_IOLIBNAME, luaopen_io}, 88 // {LUA_OSLIBNAME, luaopen_os}, 89 // {LUA_MATHLIBNAME, luaopen_math}, 90 // {LUA_UTF8LIBNAME, luaopen_utf8}, 91 // {LUA_DBLIBNAME, luaopen_debug}, 92 {"errno", luaopen_errno}, 93 {"io", luaopen_io}, 94 {"lfs", luaopen_lfs}, 95 {"loader", luaopen_loader}, 96 {"pager", luaopen_pager}, 97 {NULL, NULL} 98 }; 99 100 static void 101 interp_init_md(lua_State *L) 102 { 103 luaL_requiref(L, "gfx", luaopen_gfx, 1); 104 lua_pop(L, 1); /* Remove lib */ 105 106 /* 107 * Add in the comparability references in the loader table. Doing it with 108 * a pseudo-embedded script is easier than the raw calls. 109 */ 110 if (luaL_dostring(L, 111 "loader.fb_bezier = gfx.fb_bezier\n" 112 "loader.fb_drawrect = gfx.fb_drawrect\n" 113 "loader.fb_line = gfx.fb_line\n" 114 "loader.fb_putimage = gfx.fb_putimage\n" 115 "loader.fb_setpixel = gfx.fb_setpixel\n" 116 "loader.term_drawrect = gfx.term_drawrect\n" 117 "loader.term_putimage = gfx.term_putimage") != 0) { 118 lua_pop(L, 1); 119 const char *errstr = lua_tostring(L, -1); 120 errstr = errstr == NULL ? "unknown" : errstr; 121 printf("Error adding compat loader bindings: %s.\n", errstr); 122 } 123 } 124 125 void 126 interp_init(void) 127 { 128 lua_State *luap; 129 struct interp_lua_softc *softc = &lua_softc; 130 const char *filename; 131 const luaL_Reg *lib; 132 133 TSENTER(); 134 135 setenv("script.lang", "lua", 1); 136 LDBG("creating context"); 137 138 luap = lua_newstate(interp_lua_realloc, NULL); 139 if (luap == NULL) { 140 printf("problem initializing the Lua interpreter\n"); 141 abort(); 142 } 143 softc->luap = luap; 144 145 /* "require" functions from 'loadedlibs' and set results to global table */ 146 for (lib = loadedlibs; lib->func; lib++) { 147 luaL_requiref(luap, lib->name, lib->func, 1); 148 lua_pop(luap, 1); /* remove lib */ 149 } 150 151 interp_init_md(luap); 152 153 filename = getenv("loader_lua"); 154 if (filename == NULL) 155 filename = LOADER_LUA; 156 if (interp_include(filename) != 0) { 157 const char *errstr = lua_tostring(luap, -1); 158 errstr = errstr == NULL ? "unknown" : errstr; 159 printf("ERROR: %s.\n", errstr); 160 lua_pop(luap, 1); 161 setenv("autoboot_delay", "NO", 1); 162 } 163 164 TSEXIT(); 165 } 166 167 int 168 interp_run(const char *line) 169 { 170 int argc, nargc; 171 char **argv; 172 lua_State *luap; 173 struct interp_lua_softc *softc = &lua_softc; 174 int status, ret; 175 176 TSENTER(); 177 luap = softc->luap; 178 LDBG("executing line..."); 179 if ((status = luaL_dostring(luap, line)) != 0) { 180 lua_pop(luap, 1); 181 /* 182 * The line wasn't executable as lua; run it through parse to 183 * to get consistent parsing of command line arguments, then 184 * run it through cli_execute. If that fails, then we'll try it 185 * as a builtin. 186 */ 187 command_errmsg = NULL; 188 if (parse(&argc, &argv, line) == 0) { 189 lua_getglobal(luap, "cli_execute"); 190 for (nargc = 0; nargc < argc; ++nargc) { 191 lua_pushstring(luap, argv[nargc]); 192 } 193 status = lua_pcall(luap, argc, 1, 0); 194 ret = lua_tointeger(luap, 1); 195 lua_pop(luap, 1); 196 if (status != 0 || ret != 0) { 197 /* 198 * Lua cli_execute will pass the function back 199 * through loader.command, which is a proxy to 200 * interp_builtin_cmd. If we failed to interpret 201 * the command, though, then there's a chance 202 * that didn't happen. Call interp_builtin_cmd 203 * directly if our lua_pcall was not successful. 204 */ 205 status = interp_builtin_cmd(argc, argv); 206 } 207 if (status != 0) { 208 if (command_errmsg != NULL) 209 printf("%s\n", command_errmsg); 210 else 211 printf("Command failed\n"); 212 status = CMD_ERROR; 213 } 214 free(argv); 215 } else { 216 printf("Failed to parse \'%s\'\n", line); 217 status = CMD_ERROR; 218 } 219 } 220 221 TSEXIT(); 222 return (status == 0 ? CMD_OK : CMD_ERROR); 223 } 224 225 int 226 interp_include(const char *filename) 227 { 228 struct interp_lua_softc *softc = &lua_softc; 229 230 LDBG("loading file %s", filename); 231 232 return (luaL_dofile(softc->luap, filename)); 233 } 234