Index: head/stand/lua/color.lua =================================================================== --- head/stand/lua/color.lua (revision 329576) +++ head/stand/lua/color.lua (revision 329577) @@ -1,98 +1,98 @@ -- -- Copyright (c) 2015 Pedro Souza -- All rights reserved. -- -- Redistribution and use in source and binary forms, with or without -- modification, are permitted provided that the following conditions -- are met: -- 1. Redistributions of source code must retain the above copyright -- notice, this list of conditions and the following disclaimer. -- 2. Redistributions in binary form must reproduce the above copyright -- notice, this list of conditions and the following disclaimer in the -- documentation and/or other materials provided with the distribution. -- -- THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND -- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -- ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE -- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -- OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -- HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -- LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -- OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -- SUCH DAMAGE. -- -- $FreeBSD$ -- local color = {}; local core = require("core"); color.BLACK = 0; color.RED = 1; color.GREEN = 2; color.YELLOW = 3; color.BLUE = 4; color.MAGENTA = 5; color.CYAN = 6; color.WHITE = 7; color.DEFAULT = 0; color.BRIGHT = 1; color.DIM = 2; function color.isEnabled() local c = loader.getenv("loader_color"); if (c ~= nil) then if (c:lower() == "no") or (c == "0") then return false; end end - return (not core.bootserial()); + return (not core.isSerialBoot()); end color.disabled = (not color.isEnabled()); function color.escapef(c) if (color.disabled) then return c; end return "\027[3"..c.."m"; end function color.escapeb(c) if (color.disabled) then return c; end return "\027[4"..c.."m"; end function color.escape(fg, bg, att) if (color.disabled) then return ""; end if (not att) then att = "" else att = att..";"; end return "\027["..att.."3"..fg..";4"..bg.."m"; end function color.default() if (color.disabled) then return ""; end return "\027[0;37;40m"; end function color.highlight(str) if (color.disabled) then return str; end return "\027[1m"..str.."\027[0m"; end return color; Index: head/stand/lua/core.lua =================================================================== --- head/stand/lua/core.lua (revision 329576) +++ head/stand/lua/core.lua (revision 329577) @@ -1,216 +1,216 @@ -- -- Copyright (c) 2015 Pedro Souza -- All rights reserved. -- -- Redistribution and use in source and binary forms, with or without -- modification, are permitted provided that the following conditions -- are met: -- 1. Redistributions of source code must retain the above copyright -- notice, this list of conditions and the following disclaimer. -- 2. Redistributions in binary form must reproduce the above copyright -- notice, this list of conditions and the following disclaimer in the -- documentation and/or other materials provided with the distribution. -- -- THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND -- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -- ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE -- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -- OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -- HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -- LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -- OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -- SUCH DAMAGE. -- -- $FreeBSD$ -- local config = require('config'); local core = {}; -- Commonly appearing constants core.KEY_BACKSPACE = 8; core.KEY_ENTER = 13; core.KEY_DELETE = 127; core.KEYSTR_ESCAPE = "\027"; core.MENU_RETURN = "return"; core.MENU_ENTRY = "entry"; core.MENU_SEPARATOR = "separator"; core.MENU_SUBMENU = "submenu"; core.MENU_CAROUSEL_ENTRY = "carousel_entry"; function core.setVerbose(b) if (b == nil) then b = not core.verbose; end if (b == true) then loader.setenv("boot_verbose", "YES"); else loader.unsetenv("boot_verbose"); end core.verbose = b; end function core.setSingleUser(b) if (b == nil) then b = not core.su; end if (b == true) then loader.setenv("boot_single", "YES"); else loader.unsetenv("boot_single"); end core.su = b; end function core.getACPIPresent(checkingSystemDefaults) local c = loader.getenv("hint.acpi.0.rsdp"); if (c ~= nil) then if (checkingSystemDefaults == true) then return true; end -- Otherwise, respect disabled if it's set c = loader.getenv("hint.acpi.0.disabled"); return (c == nil) or (tonumber(c) ~= 1); end return false; end function core.setACPI(b) if (b == nil) then b = not core.acpi; end if (b == true) then loader.setenv("acpi_load", "YES"); loader.setenv("hint.acpi.0.disabled", "0"); loader.unsetenv("loader.acpi_disabled_by_user"); else loader.unsetenv("acpi_load"); loader.setenv("hint.acpi.0.disabled", "1"); loader.setenv("loader.acpi_disabled_by_user", "1"); end core.acpi = b; end function core.setSafeMode(b) if (b == nil) then b = not core.sm; end if (b == true) then loader.setenv("kern.smp.disabled", "1"); loader.setenv("hw.ata.ata_dma", "0"); loader.setenv("hw.ata.atapi_dma", "0"); loader.setenv("hw.ata.wc", "0"); loader.setenv("hw.eisa_slots", "0"); loader.setenv("kern.eventtimer.periodic", "1"); loader.setenv("kern.geom.part.check_integrity", "0"); else loader.unsetenv("kern.smp.disabled"); loader.unsetenv("hw.ata.ata_dma"); loader.unsetenv("hw.ata.atapi_dma"); loader.unsetenv("hw.ata.wc"); loader.unsetenv("hw.eisa_slots"); loader.unsetenv("kern.eventtimer.periodic"); loader.unsetenv("kern.geom.part.check_integrity"); end core.sm = b; end function core.kernelList() local k = loader.getenv("kernel"); local v = loader.getenv("kernels") or ""; local kernels = {}; local unique = {}; local i = 0; if (k ~= nil) then i = i + 1; kernels[i] = k; unique[k] = true; end for n in v:gmatch("([^; ]+)[; ]?") do if (unique[n] == nil) then i = i + 1; kernels[i] = n; unique[n] = true; end end -- Automatically detect other bootable kernel directories using a -- heuristic. Any directory in /boot that contains an ordinary file -- named "kernel" is considered eligible. for file in lfs.dir("/boot") do local fname = "/boot/" .. file; if (file == "." or file == "..") then goto continue; end if (lfs.attributes(fname, "mode") ~= "directory") then goto continue; end if (lfs.attributes(fname .. "/kernel", "mode") ~= "file") then goto continue; end if (unique[file] == nil) then i = i + 1; kernels[i] = file; unique[file] = true; end ::continue:: end return kernels; end function core.setDefaults() core.setACPI(core.getACPIPresent(true)); core.setSafeMode(false); core.setSingleUser(false); core.setVerbose(false); end function core.autoboot() config.loadelf(); loader.perform("autoboot"); end function core.boot() config.loadelf(); loader.perform("boot"); end -function core.bootserial() +function core.isSerialBoot() local c = loader.getenv("console"); if (c ~= nil) then if (c:find("comconsole") ~= nil) then return true; end end local s = loader.getenv("boot_serial"); if (s ~= nil) then return true; end local m = loader.getenv("boot_multicons"); if (m ~= nil) then return true; end return false; end core.setACPI(core.getACPIPresent(false)); return core; Index: head/stand/lua/menu.lua =================================================================== --- head/stand/lua/menu.lua (revision 329576) +++ head/stand/lua/menu.lua (revision 329577) @@ -1,408 +1,408 @@ -- -- Copyright (c) 2015 Pedro Souza -- All rights reserved. -- -- Redistribution and use in source and binary forms, with or without -- modification, are permitted provided that the following conditions -- are met: -- 1. Redistributions of source code must retain the above copyright -- notice, this list of conditions and the following disclaimer. -- 2. Redistributions in binary form must reproduce the above copyright -- notice, this list of conditions and the following disclaimer in the -- documentation and/or other materials provided with the distribution. -- -- THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND -- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -- ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE -- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -- OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -- HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -- LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -- OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -- SUCH DAMAGE. -- -- $FreeBSD$ -- local menu = {}; local core = require("core"); local color = require("color"); local config = require("config"); local screen = require("screen"); local drawer = require("drawer"); local OnOff; local skip; local run; local autoboot; local carousel_choices = {}; --loader menu tree: --rooted at menu.welcome --submenu declarations: local boot_options; local welcome; menu.boot_options = { -- return to welcome menu { entry_type = core.MENU_RETURN, name = function() return "Back to main menu"..color.highlight(" [Backspace]"); end }, -- load defaults { entry_type = core.MENU_ENTRY, name = function() return "Load System "..color.highlight("D").."efaults"; end, func = function() core.setDefaults(); end, alias = {"d", "D"} }, { entry_type = core.MENU_SEPARATOR, name = function() return ""; end }, { entry_type = core.MENU_SEPARATOR, name = function() return "Boot Options:"; end }, -- acpi { entry_type = core.MENU_ENTRY, name = function() return OnOff(color.highlight("A").."CPI :", core.acpi); end, func = function() core.setACPI(); end, alias = {"a", "A"} }, -- safe mode { entry_type = core.MENU_ENTRY, name = function() return OnOff("Safe "..color.highlight("M").."ode :", core.sm); end, func = function() core.setSafeMode(); end, alias = {"m", "M"} }, -- single user { entry_type = core.MENU_ENTRY, name = function() return OnOff(color.highlight("S").."ingle user:", core.su); end, func = function() core.setSingleUser(); end, alias = {"s", "S"} }, -- verbose boot { entry_type = core.MENU_ENTRY, name = function() return OnOff(color.highlight("V").."erbose :", core.verbose); end, func = function() core.setVerbose(); end, alias = {"v", "V"} }, }; menu.welcome = { -- boot multi user { entry_type = core.MENU_ENTRY, name = function() return color.highlight("B").."oot Multi user "..color.highlight("[Enter]"); end, func = function() core.setSingleUser(false); core.boot(); end, alias = {"b", "B"} }, -- boot single user { entry_type = core.MENU_ENTRY, name = function() return "Boot "..color.highlight("S").."ingle user"; end, func = function() core.setSingleUser(true); core.boot(); end, alias = {"s", "S"} }, -- escape to interpreter { entry_type = core.MENU_RETURN, name = function() return color.highlight("Esc").."ape to loader prompt"; end, func = function() loader.setenv("autoboot_delay", "NO"); end, alias = {core.KEYSTR_ESCAPE} }, -- reboot { entry_type = core.MENU_ENTRY, name = function() return color.highlight("R").."eboot"; end, func = function() loader.perform("reboot"); end, alias = {"r", "R"} }, { entry_type = core.MENU_SEPARATOR, name = function() return ""; end }, { entry_type = core.MENU_SEPARATOR, name = function() return "Options:"; end }, -- kernel options { entry_type = core.MENU_CAROUSEL_ENTRY, carousel_id = "kernel", items = core.kernelList, name = function(idx, choice, all_choices) if (#all_choices == 0) then return "Kernel: "; end local is_default = (idx == 1); local kernel_name = ""; local name_color; if (is_default) then name_color = color.escapef(color.GREEN); kernel_name = "default/"; else name_color = color.escapef(color.BLUE); end kernel_name = kernel_name .. name_color .. choice .. color.default(); return color.highlight("K").."ernel: " .. kernel_name .. " (" .. idx .. " of " .. #all_choices .. ")"; end, func = function(idx, choice, all_choices) config.selectkernel(choice); end, alias = {"k", "K"} }, -- boot options { entry_type = core.MENU_SUBMENU, name = function() return "Boot "..color.highlight("O").."ptions"; end, submenu = function() return menu.boot_options; end, alias = {"o", "O"} } }; -- The first item in every carousel is always the default item. function menu.getCarouselIndex(id) local val = carousel_choices[id]; if (val == nil) then return 1; end return val; end function menu.setCarouselIndex(id, idx) carousel_choices[id] = idx; end function menu.run(m) if (menu.skip()) then core.autoboot(); return false; end if (m == nil) then m = menu.welcome; end -- redraw screen screen.clear(); screen.defcursor(); local alias_table = drawer.drawscreen(m); menu.autoboot(); cont = true; while (cont) do local key = io.getchar(); -- Special key behaviors if ((key == core.KEY_BACKSPACE) or (key == core.KEY_DELETE)) and (m ~= menu.welcome) then break elseif (key == core.KEY_ENTER) then core.boot(); -- Should not return end key = string.char(key) -- check to see if key is an alias local sel_entry = nil; for k, v in pairs(alias_table) do if (key == k) then sel_entry = v; end end -- if we have an alias do the assigned action: if (sel_entry ~= nil) then if (sel_entry.entry_type == core.MENU_ENTRY) then -- run function sel_entry.func(); elseif (sel_entry.entry_type == core.MENU_CAROUSEL_ENTRY) then -- carousel (rotating) functionality local carid = sel_entry.carousel_id; local caridx = menu.getCarouselIndex(carid); local choices = sel_entry.items(); if (#choices > 0) then caridx = (caridx % #choices) + 1; menu.setCarouselIndex(carid, caridx); sel_entry.func(caridx, choices[caridx], choices); end elseif (sel_entry.entry_type == core.MENU_SUBMENU) then -- recurse cont = menu.run(sel_entry.submenu()); elseif (sel_entry.entry_type == core.MENU_RETURN) then -- allow entry to have a function/side effect if (sel_entry.func ~= nil) then sel_entry.func(); end -- break recurse cont = false; end -- if we got an alias key the screen is out of date: screen.clear(); screen.defcursor(); alias_table = drawer.drawscreen(m); end end if (m == menu.welcome) then screen.defcursor(); print("Exiting menu!"); config.loadelf(); return false; end return true; end function menu.skip() - if (core.bootserial() )then + if (core.isSerialBoot())then return true; end local c = string.lower(loader.getenv("console") or ""); if ((c:match("^efi[ ;]") or c:match("[ ;]efi[ ;]")) ~= nil) then return true; end c = string.lower(loader.getenv("beastie_disable") or ""); print("beastie_disable", c); return c == "yes"; end function menu.autoboot() if (menu.already_autoboot == true) then return; end menu.already_autoboot = true; local ab = loader.getenv("autoboot_delay"); if (ab ~= nil) and (ab:lower() == "no") then return; elseif (tonumber(ab) == -1) then core.boot(); end ab = tonumber(ab) or 10; local x = loader.getenv("loader_menu_timeout_x") or 5; local y = loader.getenv("loader_menu_timeout_y") or 22; local endtime = loader.time() + ab; local time; repeat time = endtime - loader.time(); screen.setcursor(x, y); print("Autoboot in "..time.." seconds, hit [Enter] to boot" .." or any other key to stop "); screen.defcursor(); if (io.ischar()) then local ch = io.getchar(); if (ch == core.KEY_ENTER) then break; else -- erase autoboot msg screen.setcursor(0, y); print(" " .." "); screen.defcursor(); return; end end loader.delay(50000); until time <= 0 core.boot(); end function OnOff(str, b) if (b) then return str .. color.escapef(color.GREEN).."On"..color.escapef(color.WHITE); else return str .. color.escapef(color.RED).."off"..color.escapef(color.WHITE); end end return menu; Index: head/stand/lua/screen.lua =================================================================== --- head/stand/lua/screen.lua (revision 329576) +++ head/stand/lua/screen.lua (revision 329577) @@ -1,85 +1,85 @@ -- -- Copyright (c) 2015 Pedro Souza -- All rights reserved. -- -- Redistribution and use in source and binary forms, with or without -- modification, are permitted provided that the following conditions -- are met: -- 1. Redistributions of source code must retain the above copyright -- notice, this list of conditions and the following disclaimer. -- 2. Redistributions in binary form must reproduce the above copyright -- notice, this list of conditions and the following disclaimer in the -- documentation and/or other materials provided with the distribution. -- -- THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND -- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -- ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE -- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -- OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -- HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -- LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -- OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -- SUCH DAMAGE. -- -- $FreeBSD$ -- local screen = {}; local color = require("color"); local core = require("core"); -- XXX TODO: This should be fixed in the interpreter to not print decimals function intstring(num) local str = tostring(num); local decimal = str:find("%."); if (decimal) then return str:sub(1, decimal - 1); end return str; end function screen.clear() - if (core.bootserial()) then + if (core.isSerialBoot()) then return; end loader.printc("\027[H\027[J"); end function screen.setcursor(x, y) - if (core.bootserial()) then + if (core.isSerialBoot()) then return; end loader.printc("\027["..intstring(y)..";"..intstring(x).."H"); end function screen.setforeground(c) if (color.disabled) then return c; end loader.printc("\027[3"..c.."m"); end function screen.setbackground(c) if (color.disabled) then return c; end loader.printc("\027[4"..c.."m"); end function screen.defcolor() loader.printc(color.default()); end function screen.defcursor() - if (core.bootserial()) then + if (core.isSerialBoot()) then return; end loader.printc("\027[25;0H"); end return screen;