From a562f1c87424a58daea16dc0bd8801211817c116 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ferenc=20W=C3=A1gner?= Date: Tue, 25 Feb 2014 19:18:27 +0100 Subject: lua: replace the syslinux module test with an automatic boot menu generator --- com32/lua/test/automenu.lua | 152 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 152 insertions(+) create mode 100644 com32/lua/test/automenu.lua diff --git a/com32/lua/test/automenu.lua b/com32/lua/test/automenu.lua new file mode 100644 index 00000000..1e66cca1 --- /dev/null +++ b/com32/lua/test/automenu.lua @@ -0,0 +1,152 @@ +--[[ +Automatically generated boot menu of the installed Linux kernels + +Example: + +m = require "automenu" +m.run { dir = "/", + default = 1, + timeout = 5, + append = "root=/dev/hda2 ro", +} + +TODO: +- add hooks +- demo adding break options from user config +- kernel flavor preference (pae/rt) +]] + +local lfs = require "lfs" +local sl = require "syslinux" + +local single = false +local verbosity = 2 + +local function modifiers () + return (single and " single" or "") .. ({" quiet",""," debug"})[verbosity] +end + +local function scan (params) + local sep = string.sub (params.dir, -1) == "/" and "" or "/" + if not params.items then params.items = {} end + for name in lfs.dir (params.dir) do + local path = params.dir .. sep .. name + if lfs.attributes (path, "mode") == "file" then + local from,to,version = string.find (name, "^vmlinuz%-(.*)") + if from then + local initrd = params.dir .. sep .. "initrd.img-" .. version + local initrd_param = "" + if lfs.attributes (initrd, "size") then + initrd_param = "initrd=" .. initrd .. " " + end + table.insert (params.items, { + show = function () return name end, + version = version, + execute = function () sl.boot_linux (path, initrd_param .. params.append .. modifiers ()) end + }) + end + end + end +end + +local function version_gt (v1, v2) + local negatives = {"rc", "pre"} + local m1, r1 = string.match (v1, "^(%D*)(.*)") + local m2, r2 = string.match (v2, "^(%D*)(.*)") + if m1 ~= m2 then + for _, suffix in ipairs (negatives) do + suffix = "-" .. suffix + if m1 == suffix and m2 ~= suffix then + return false + elseif m1 ~= suffix and m2 == suffix then + return true + end + end + return m1 > m2 + end + m1, r1 = string.match (r1, "^(%d*)(.*)") + m2, r2 = string.match (r2, "^(%d*)(.*)") + m1 = tonumber (m1) or 0 + m2 = tonumber (m2) or 0 + if m1 ~= m2 then + return m1 > m2 + end + if r1 == "" and r2 == "" then + return false + end + return version_gt (r1, r2) +end + +local function kernel_gt (k1, k2) + return version_gt (k1.version, k2.version) +end + +local function print_or_call (x, def) + local t = type (x) + if t == "nil" then + if def then print (def) end + elseif t == "function" then + x () + else + print (x) + end +end + +local function draw (params) + print_or_call (params.title, "\n=== Boot menu ===") + for i, item in ipairs (params.items) do + print ((i == params.default and " > " or " ") .. i .. " " .. item.show ()) + end + print ("\nKernel arguments:\n " .. params.append .. modifiers ()) + print ("\nHit a number to select from the menu,\n ENTER to accept default,\n ESC to exit\n or any other key to print menu again") +end + +local function choose (params) + draw (params) + print ("\nBooting in " .. params.timeout .. " s...") + while true do + local i = sl.get_key (params.timeout * 1000) + if i == sl.KEY.ESC then + break + else + if i == sl.KEY.NONE or i == sl.KEY.ENTER then + i = params.default + elseif i == sl.KEY.DOWN then + params.default = params.default < #params.items and params.default + 1 or #params.items + elseif i == sl.KEY.UP then + params.default = params.default > 1 and params.default - 1 or 1 + else + i = i - string.byte "0" + end + if params.items[i] then + params.items[i].execute () + end + params.timeout = 0 + draw (params) + end + end +end + +local function run (params) + scan (params) + if not next (params.items) then + print ("No kernels found in directory " .. params.dir) + os.exit (false) + end + table.sort (params.items, kernel_gt) + table.insert (params.items, { + show = function () return "Single user: " .. (single and "true" or "false") end, + execute = function () single = not single end + }) + table.insert (params.items, { + show = function () return "Verbosity: " .. ({"quiet","normal","debug"})[verbosity] end, + execute = function () verbosity = verbosity < 3 and verbosity + 1 or 1 end + }) + choose (params) +end + +return { + scan = scan, + choose = choose, + run = run +} -- cgit v1.2.1