/*-1* Copyright (c) 2011 Wojciech A. Koszek <[email protected]>2* Copyright (c) 2014 Pedro Souza <[email protected]>3* All rights reserved.4*5* Redistribution and use in source and binary forms, with or without6* modification, are permitted provided that the following conditions7* are met:8* 1. Redistributions of source code must retain the above copyright9* notice, this list of conditions and the following disclaimer.10* 2. Redistributions in binary form must reproduce the above copyright11* notice, this list of conditions and the following disclaimer in the12* documentation and/or other materials provided with the distribution.13*14* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND15* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE16* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE17* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE18* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL19* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS20* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)21* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT22* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY23* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF24* SUCH DAMAGE.25*/2627#include <stand.h>28#include "bootstrap.h"2930#define lua_c3132#include "lstd.h"3334#include <lua.h>35#include <ldebug.h>36#include <lauxlib.h>37#include <lualib.h>3839#include <lerrno.h>40#include <lfs.h>41#include <lutils.h>4243struct interp_lua_softc {44lua_State *luap;45};4647static struct interp_lua_softc lua_softc;4849#ifdef LUA_DEBUG50#define LDBG(...) do { \51printf("%s(%d): ", __func__, __LINE__); \52printf(__VA_ARGS__); \53printf("\n"); \54} while (0)55#else56#define LDBG(...)57#endif5859#define LOADER_LUA LUA_PATH "/loader.lua"6061INTERP_DEFINE("lua");6263static void *64interp_lua_realloc(void *ud __unused, void *ptr, size_t osize __unused, size_t nsize)65{6667if (nsize == 0) {68free(ptr);69return NULL;70}71return realloc(ptr, nsize);72}7374/*75* The libraries commented out below either lack the proper76* support from libsa, or they are unlikely to be useful77* in the bootloader, so have been commented out.78*/79static const luaL_Reg loadedlibs[] = {80{"_G", luaopen_base},81{LUA_LOADLIBNAME, luaopen_package},82// {LUA_COLIBNAME, luaopen_coroutine},83// {LUA_TABLIBNAME, luaopen_table},84{LUA_STRLIBNAME, luaopen_string},85// {LUA_IOLIBNAME, luaopen_io},86// {LUA_OSLIBNAME, luaopen_os},87// {LUA_MATHLIBNAME, luaopen_math},88// {LUA_UTF8LIBNAME, luaopen_utf8},89// {LUA_DBLIBNAME, luaopen_debug},90{"errno", luaopen_errno},91{"io", luaopen_io},92{"lfs", luaopen_lfs},93{"loader", luaopen_loader},94{"pager", luaopen_pager},95{NULL, NULL}96};9798static bool preinit_done = false;99100void101interp_preinit(void)102{103lua_State *luap;104struct interp_lua_softc *softc = &lua_softc;105const luaL_Reg *lib;106lua_init_md_t **fnpp;107108TSENTER();109110if (preinit_done)111return;112113setenv("script.lang", "lua", 1);114LDBG("creating context");115116luap = lua_newstate(interp_lua_realloc, NULL);117if (luap == NULL) {118printf("problem initializing the Lua interpreter\n");119abort();120}121softc->luap = luap;122123/* "require" functions from 'loadedlibs' and set results to global table */124for (lib = loadedlibs; lib->func; lib++) {125luaL_requiref(luap, lib->name, lib->func, 1);126lua_pop(luap, 1); /* remove lib */127}128129LUA_FOREACH_SET(fnpp)130(*fnpp)(luap);131132preinit_done = true;133134TSEXIT();135}136137void138interp_init(void)139{140lua_State *luap;141struct interp_lua_softc *softc = &lua_softc;142const char *filename;143144TSENTER();145146luap = softc->luap;147filename = getenv("loader_lua");148if (filename == NULL)149filename = LOADER_LUA;150if (interp_include(filename) != 0) {151const char *errstr = lua_tostring(luap, -1);152errstr = errstr == NULL ? "unknown" : errstr;153printf("ERROR: %s.\n", errstr);154lua_pop(luap, 1);155setenv("autoboot_delay", "NO", 1);156}157158TSEXIT();159}160161int162interp_run(const char *line)163{164int argc, nargc;165char **argv;166lua_State *luap;167struct interp_lua_softc *softc = &lua_softc;168int status, ret;169170TSENTER();171luap = softc->luap;172LDBG("executing line...");173if ((status = luaL_dostring(luap, line)) != 0) {174lua_pop(luap, 1);175/*176* The line wasn't executable as lua; run it through parse to177* to get consistent parsing of command line arguments, then178* run it through cli_execute. If that fails, then we'll try it179* as a builtin.180*/181command_errmsg = NULL;182if (parse(&argc, &argv, line) == 0) {183lua_getglobal(luap, "cli_execute");184for (nargc = 0; nargc < argc; ++nargc) {185lua_pushstring(luap, argv[nargc]);186}187status = lua_pcall(luap, argc, 1, 0);188ret = lua_tointeger(luap, 1);189lua_pop(luap, 1);190if (status != 0 || ret != 0) {191/*192* Lua cli_execute will pass the function back193* through loader.command, which is a proxy to194* interp_builtin_cmd. If we failed to interpret195* the command, though, then there's a chance196* that didn't happen. Call interp_builtin_cmd197* directly if our lua_pcall was not successful.198*/199status = interp_builtin_cmd(argc, argv);200}201if (status != 0) {202if (command_errmsg != NULL)203printf("%s\n", command_errmsg);204else205printf("Command failed\n");206status = CMD_ERROR;207}208free(argv);209} else {210printf("Failed to parse \'%s\'\n", line);211status = CMD_ERROR;212}213}214215TSEXIT();216return (status == 0 ? CMD_OK : CMD_ERROR);217}218219int220interp_include(const char *filename)221{222struct interp_lua_softc *softc = &lua_softc;223224LDBG("loading file %s", filename);225226return (luaL_dofile(softc->luap, filename));227}228229230