-- [ʞ] tools/makeshim.lua
-- ~ lexi hale <lexi@hale.su>
-- 🄯 AGPLv3
-- ? this program creates a C source file embedding
-- cortav, for the purposes of standalone deployment
-- without a lua interpreter, or for the purposes of
-- giving cortav extra privileges
local includes = [[
#include <lua.h>
#include <lauxlib.h>
#include <stdio.h>
#include <stddef.h>
#include <unistd.h>
extern int luaL_openlibs(lua_State* l);
]]
local main = [[
int main(int argc, char** argv) {
lua_State* l = luaL_newstate();
luaL_openlibs(l);
// pass arguments thru to lua
lua_newtable(l);
for(size_t i = 0; i < argc; ++i) {
lua_pushstring(l,argv[i]);
lua_rawseti(l, -2, i);
}
lua_setglobal(l, "arg");
// load and run our payload
int e = luaL_loadbufferx(l, ct_bytecode, sizeof(ct_bytecode), "cortav", "b");
if (e != LUA_OK) {
printf("some kind of error idk fam\n");
return -1;
}
// create the native interface table, if nothing
// else to signal that cortav is running under a
// binary shim
lua_pushglobaltable(l);
lua_newtable(l);
_lua_env_setup
lua_setfield(l, -2, "native");
lua_pop(l, 1);
if (lua_pcall(l, 0, 0, 0) != LUA_OK) {
size_t len;
const char* msg = luaL_tolstring(l, -1, &len);
if (isatty(2)) {
fprintf(stderr, "\33[31;1m(fatal)\33[m %.*s\n", (int)len, msg);
} else {
fprintf(stderr, "(fatal) %.*s\n", (int)len, msg);
}
};
// normal termination is by the os.exit() call
return -1;
}
]]
local function setfile(i, dflt, mode)
if arg[i] and arg[i] ~= '' then
local fn = io.open(arg[i], mode)
if fn then
return fn
end
io.stderr:write('(' .. arg[0]..' fatal) cannot open file '..arg[i])
end
return dflt
end
local src = setfile(1, io.stdin, "rb")
local dest = setfile(2, io.stdout, "w")
local binds = {}
for i=3,#arg do
io.stderr:write(string.format("(%s info) including loader for bind %s\n", arg[0], arg[i]))
table.insert(binds, arg[i])
end
local cstr = {}
local strtpl = [[static char ct_bytecode [%u] = {
%s
};]]
local bindfn = [[#define _lua_env_setup]]
if next(binds) then
-- make cpp do our interpolation for us
bindfn = [[#define _lua_env_setup init_binds(l);]]
local calls = {}
local decls = {}
local ctpl = [[
luaopen_bind_%s(l);
lua_setfield(l, -2, "%s");
]]
for n,b in ipairs(binds) do
table.insert(decls, string.format('extern int luaopen_bind_%s(lua_State* l);\n', b))
table.insert(calls, string.format(ctpl, b, b))
end
local hdr = [[
static void init_binds(lua_State* l) {
]]
local foot = [[
}
]]
bindfn = bindfn .. '\n'
.. table.concat(decls)
.. hdr
.. table.concat(calls)
.. foot
end
local bytes = {}
local bn = 1
local len = 0
while true do
local byte = src:read(1)
if not byte then break end
local str = tostring(byte:byte(1))..','
-- make sure our source file is parseable by
-- a compliant C compiler
local strl = string.len(str)
if len + strl >= 4095 then
len = 0
bytes[bn]='\n'
bn = bn + 1
end
len = len + strl
bytes[bn] = str
bn = bn + 1
end
local lines = {
includes;
strtpl:format(#bytes, table.concat(bytes));
bindfn;
main;
}
dest:write(table.concat(lines, '\n'))