Index: stand/common/interp_lua.c =================================================================== --- stand/common/interp_lua.c +++ stand/common/interp_lua.c @@ -43,6 +43,7 @@ #include #include #include +#include struct interp_lua_softc { lua_State *luap; @@ -124,10 +125,26 @@ filename = LOADER_LUA; if (interp_include(filename) != 0) { - const char *errstr = lua_tostring(luap, -1); - errstr = errstr == NULL ? "unknown" : errstr; - printf("Startup error in %s:\nLUA ERROR: %s.\n", filename, errstr); - lua_pop(luap, 1); + if (lua_isnumber(luap, -1)) { + lua_Number exit_code; + + exit_code = lua_tonumber(luap, -1); + lua_pop(luap, 1); + + /* + * INTERP_ERROR_EXIT is a fake error that indicates that + * should just return and continue the loader sequence. + */ + if (exit_code != INTERP_ERROR_EXIT) + printf("Startup error in %s, exit code %jd.\n", + filename, (intmax_t)exit_code); + } else { + const char *errstr = lua_tostring(luap, -1); + errstr = errstr == NULL ? "unknown" : errstr; + printf("Startup error in %s:\nLUA ERROR: %s.\n", + filename, errstr); + lua_pop(luap, 1); + } } } Index: stand/liblua/lstd.h =================================================================== --- stand/liblua/lstd.h +++ stand/liblua/lstd.h @@ -80,4 +80,17 @@ #define fflush /* */ #define fgets(b, l, s) fgetstr((b), (l), 0) +/* + * We get one object to represent an error when returning from within the lua + * pcall context. To avoid colliding with perhaps other legitimate error + * circumstances, we derive the below magic number and use that as our basis for + * errors. This 'b', 's', 'd' magic should hopefully be unique enough that we + * can determine that this is the kind of error we think it is. Also note that + * Lua itself uses strings for its error objects, so we're likely pretty safe + * anyways. + */ +#define INTERP_ERROR_MAGIC (0x62736400) +#define INTERP_ERROR(n) (INTERP_ERROR_MAGIC + (n)) +#define INTERP_ERROR_EXIT INTERP_ERROR(0) + #endif /* LSTD_H */ Index: stand/liblua/lutils.c =================================================================== --- stand/liblua/lutils.c +++ stand/liblua/lutils.c @@ -36,6 +36,29 @@ #include "lutils.h" #include "bootstrap.h" +/* + * Exits the interpreter cleanly, proceeding to autoboot or loader prompt + * depending on configuration. + */ +static int +lua_exit(lua_State *L) +{ + + /* + * Be strict about parameters for now, in case we want to change usage + * down the road. + */ + if (lua_gettop(L) != 0) + lua_pushliteral(L, + "loader.exit() must not be called with arguments."); + else + lua_pushnumber(L, INTERP_ERROR_EXIT); + + lua_error(L); + /* NORETURN */ + return (1); +} + /* * Like loader.perform, except args are passed already parsed * on the stack. @@ -351,6 +374,7 @@ REG_SIMPLE(delay), REG_SIMPLE(command_error), REG_SIMPLE(command), + REG_SIMPLE(exit), REG_SIMPLE(interpret), REG_SIMPLE(parse), REG_SIMPLE(getenv),