#!/usr/bin/lua
--
-- SPDX-FileCopyrightText: (c) 2023-2024 Ring Zero Desenvolvimento de Software LTDA
-- SPDX-License-Identifier: MIT OR GPL-2.0-only
--

local lunatik = {
	copyright = "Copyright (C) 2023-2024 ring-0 Ltda.",
	device = "/dev/lunatik",
	modules = {"lunatik", "luadevice", "lualinux", "luanotifier", "luasocket", "luarcu",
		"luathread", "luafib", "luadata", "luaprobe", "luasyscall", "luaxdp", "luafifo", "luaxtable",
		"luanetfilter", "luacompletion", "lunatik_run"}
}

function lunatik.prompt()
	io.write("> ")
	io.flush()
end

function lunatik.open(mode)
	return io.open(lunatik.device, mode)
end

function lunatik.probe()
	local prober <close> = lunatik.open("r")
	return prober and true or false
end

function lunatik.loadstring(chunk)
	local loader <close> = assert(lunatik.open("r+"))
	loader:write(chunk)
end

function lunatik.result()
	local reader <close> = lunatik.open("r")
	return reader:read("a")
end

function lunatik.dostring(chunk)
	lunatik.loadstring(chunk)
	return lunatik.result()
end

function lunatik.usage()
	print("usage: lunatik [load|unload|reload|status|list] [run|spawn|stop <script>]")
	os.exit(false)
end

function lunatik.sh(command, module, loaded)
	local isloaded = loaded and "&&" or "||"
	os.execute(string.format("MODULE=%s;grep -wq $MODULE /proc/modules %s%s", module, isloaded, command))
end

lunatik.commands = {
	['load'] = function ()
		for _, module in ipairs(lunatik.modules) do
			local path = "/lib/modules/`uname -r`/lunatik"
			lunatik.sh("modprobe -s $MODULE || insmod " .. path .. "/$MODULE.ko", module)
		end

		if not lunatik.probe() then
			error("couldn't create " .. lunatik.device)
		end

		local result = lunatik.dostring[[
			lunatik = require("lunatik")
			lunatik.runner = require("lunatik.runner")
			lunatik.runner.startup()
		]]
		if result ~= "" then error(result) end
	end,
	['unload'] = function ()
		if lunatik.probe() then
			lunatik.dostring("lunatik.runner.shutdown()")
		end

		local first = #lunatik.modules
		for i = first, 1, -1 do
			local module = lunatik.modules[i]
			lunatik.sh("rmmod $MODULE", module, true)
		end
	end,
	['reload'] = function()
		local commands = lunatik.commands
		commands.unload()
		commands.load()
	end,
	['status'] = function ()
		for _, module in ipairs(lunatik.modules) do
			lunatik.sh("echo $MODULE is loaded || echo $MODULE is not loaded", module, true)
		end
	end
}

local command = lunatik.commands[arg[1]]
if command then
	command()
	os.exit()
end

if not lunatik.probe() then
	lunatik.commands.load()
end

local version = lunatik.dostring("return _LUNATIK_VERSION")
lunatik.copyright = version .. "  " .. lunatik.copyright

local function set(t)
	local s = {}
	for _, key in ipairs(t) do s[key] = true end
	return s
end

local tokens = set{"run", "spawn", "stop", "list"}

if #arg >= 1 then
	local token = arg[1]
	local script = arg[2]
	local parm = arg[3]
	if tokens[token] then
		local parm = parm and ("," .. parm) or ""
		local ret = token == "list" and "return" or ""
		local chunk = string.format("%s lunatik.runner.%s('%s'%s)", ret, token, script, parm)
		print(lunatik.dostring(chunk))
	else
		lunatik.usage()
	end
	os.exit()
end

print(lunatik.copyright)
lunatik.prompt()
for chunk in io.lines() do
	print(lunatik.dostring(chunk))
	lunatik.prompt()
end

