#!/opt/lnxall_app/bin/lua

-- Created by jiaqiang.ye@lnxall.com
-- Simple upstart for application installation
-- 2025/08/12

local invoker = require "invoker"
local gfmt = string.format

local g_shell    = "/bin/bash"
local g_UPDIR    = "/opt/lnxall_app/app/upstart"
local g_UPTAG    = nil
local g_UPLOCK   = "/tmp/.upstart.lock"
local g_TMPDIR   = "/tmp/.upstart.home"
local g_lockfd   = nil

local function lupstart_init()
	-- Created temporary directory:
	invoker.mkdir(g_TMPDIR)
	if not invoker.chdir(g_TMPDIR) then
		io.stderr:write(gfmt("Error, directory not found: %s\n", g_TMPDIR))
		io.stderr:flush()
		os.exit(1)
	end

	-- Get UPSTART Directory from environment variable:
	local updir = os.getenv("LUPSTART_DIR")
	if type(updir) == "string" and #updir > 0 then
		g_UPDIR = updir
	end

	-- Get UPSTART TAG Directory from environment variable:
	updir = os.getenv("LUPSTART_TAGDIR")
	if type(updir) == "string" and #updir > 0 then
		g_UPTAG = updir
	else
		g_UPTAG = g_UPDIR
	end

	-- determine shell executable
	if not invoker.statfile(g_shell) then
		g_shell = "/bin/sh"
	end

	-- close any lingering file descriptors
	for ifd = 3, 64 do
		invoker.closefd(ifd)
	end
	io.stdout:write(gfmt("UPSTART_DIR: %s, TAGDIR: %s\n", g_UPDIR, g_UPTAG))
	io.stdout:flush()

	-- acquire file system lock
	local lockfd = invoker.waitlock(g_UPLOCK)
	if not lockfd then
		io.stderr:write(gfmt("Error, failed to acquire file-lock: %s\n", g_UPLOCK))
		io.stderr:flush()
		os.exit(2)
	end
	g_lockfd = lockfd
	return true
end

local function lupstart_run(ups, upfile, tagfile)
	io.stdout:write(gfmt("Running upstart script: %s ...\n", upfile))
	io.stdout:flush()

	local pid = invoker.invoke(invoker.NOWAIT, g_shell, ups, "install")
	if not pid then
		io.stderr:write(gfmt("Error, failed to run script: %s\n", ups))
		io.stderr:flush()
		return false
	end

	local exited, exitval = false, 0
	local wbegin, dokill = invoker.uptime() + 90, true
	while wbegin > invoker.uptime() do
		exited, exitval = invoker.waitpid(pid, true)
		if exited == nil or exited then
			dokill = false
			break
		end
		invoker.msleep(320)
	end

	if dokill then
		exitval = 2024
		if not invoker.kill(pid, 9) then invoker.kill(pid, 9) end
		io.stderr:write(gfmt("Error, killing upstart script: %s\n", ups))
		io.stderr:flush()
		invoker.waitpid(pid, false)
	end

	if type(exitval) ~= "number" then exitval = 2025 end
	local tfp = io.open(tagfile, "wb")
	if not tfp then
		io.stderr:write(gfmt("Error, failed to open tagfile: %s\n", tagfile))
		io.stderr:flush()
		return false
	end
	tfp:write(gfmt("%s: %s => exited with: %d\n", os.date(), upfile, exitval))
	tfp:close(); tfp = nil

	io.stdout:write(gfmt("Script '%s' exited with: %d\n", upfile, exitval))
	io.stdout:flush()
	return true
end

local function lupstart_main()
	local lups = invoker.glob(gfmt("%s/*.sh", g_UPDIR))
	if type(lups) ~= "table" then
		io.stderr:write(gfmt("Error, no upstart scripts found in %s\n", g_UPDIR))
		io.stderr:flush()
		return false
	end

	for _, upscript in ipairs(lups) do
		local scriptn = string.match(upscript, "/([^/]+)$") or "NOTFOUND"
		local tagpath = gfmt("%s/.%s.done", g_UPTAG, scriptn)
		local typf, size = invoker.statfile(upscript)
		if typf == "regular" and size > 0 and not invoker.statfile(tagpath) then
			lupstart_run(upscript, scriptn, tagpath)
		end
	end
	return true
end

lupstart_init()
lupstart_main()
os.exit(0)
