-- Reads tools/catalog.lua and stamps out the -srv/-log longrun pairs and -- agetty-tty1..6 under services/. Authored/run on the Windows box with -- lua55; portable enough to rerun on a real Linux target later. Files are -- written with explicit "\n" line endings in binary mode so Windows doesn't -- translate them to CRLF. -- -- Usage: lua55 tools/gen-services.lua local script_dir = arg[0]:match("^(.*)[/\\][^/\\]*$") or "." local repo_root = script_dir .. "/.." local services_dir = repo_root .. "/services" local catalog = dofile(script_dir .. "/catalog.lua") local function is_windows() return package.config:sub(1, 1) == "\\" end local function mkdir_p(path) if is_windows() then local winpath = path:gsub("/", "\\") os.execute('if not exist "' .. winpath .. '" mkdir "' .. winpath .. '" >nul 2>nul') else os.execute('mkdir -p "' .. path .. '"') end end local function dirname(path) return path:match("^(.*)[/\\][^/\\]*$") or "." end local function write_file(path, content) mkdir_p(dirname(path)) local f = assert(io.open(path, "wb")) f:write(content) f:close() end local function touch(path) write_file(path, "") end local function lua_array_literal(items) local parts = {} for i, v in ipairs(items) do parts[i] = string.format("%q", v) end return "{ " .. table.concat(parts, ", ") .. " }" end local function render_srv_run(argv) return string.format( "#!/usr/bin/lua\nlocal s6 = require(\"s6lua\")\ns6.exec(%s)\n", lua_array_literal(argv) ) end local function render_finish(tag) return string.format( "#!/usr/bin/lua\nlocal s6 = require(\"s6lua\")\ns6.log(%q, \"exited (code=%%s signal=%%s)\", arg[1], arg[2])\n", tag ) end local function render_log_run(log_dir) return string.format( "#!/usr/bin/lua\nlocal s6 = require(\"s6lua\")\ns6.mkdirp(%q)\ns6.exec({ \"/usr/bin/s6-log\", \"-b\", \"n20\", \"s10000000\", %q })\n", log_dir, log_dir ) end local function render_agetty_run(n) return render_srv_run({ "/sbin/agetty", "tty" .. tostring(n), "38400", "linux" }) end for _, d in ipairs(catalog.daemons) do local srv_dir = services_dir .. "/" .. d.srv local log_svc_dir = services_dir .. "/" .. d.log write_file(srv_dir .. "/type", "longrun\n") write_file(srv_dir .. "/run", render_srv_run(d.argv)) write_file(srv_dir .. "/finish", render_finish(d.key)) write_file(srv_dir .. "/producer-for", d.log .. "\n") for _, dep in ipairs(d.deps) do touch(srv_dir .. "/dependencies.d/" .. dep) end write_file(log_svc_dir .. "/type", "longrun\n") write_file(log_svc_dir .. "/run", render_log_run(d.log_dir)) write_file(log_svc_dir .. "/consumer-for", d.srv .. "\n") write_file(log_svc_dir .. "/pipeline-name", d.key .. "\n") print("generated " .. d.srv .. " / " .. d.log) end if catalog.ttys and #catalog.ttys > 0 then local ttys_dir = services_dir .. "/ttys" write_file(ttys_dir .. "/type", "bundle\n") for _, n in ipairs(catalog.ttys) do local name = "agetty-tty" .. tostring(n) local dir = services_dir .. "/" .. name write_file(dir .. "/type", "longrun\n") write_file(dir .. "/run", render_agetty_run(n)) touch(ttys_dir .. "/contents.d/" .. name) print("generated " .. name) end end print("done")