Index: stand/Makefile =================================================================== --- stand/Makefile +++ stand/Makefile @@ -10,6 +10,7 @@ .endif .if ${MK_LOADER_LUA} != "no" SUBDIR+= liblua +SUBDIR+= lua .endif SUBDIR+= man Index: stand/lua/Makefile =================================================================== --- /dev/null +++ stand/lua/Makefile @@ -0,0 +1,15 @@ +# $FreeBSD$ + +.include + +BINDIR= /boot/lua +FILES= color.lua \ + config.lua \ + core.lua \ + drawer.lua \ + loader.lua \ + menu.lua \ + password.lua \ + screen.lua + +.include Index: stand/lua/color.lua =================================================================== --- /dev/null +++ stand/lua/color.lua @@ -0,0 +1,99 @@ +-- +-- 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(); +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: stand/lua/config.lua =================================================================== --- /dev/null +++ stand/lua/config.lua @@ -0,0 +1,371 @@ +-- +-- 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 = {}; + +local modules = {}; + +function config.setKey(k, n, v) + if modules[k] == nil then + modules[k] = {}; + end + modules[k][n] = v; +end + +local pattern_table = { + [1] = { + str = "^%s*(#.*)", + process = function(k, v) end + }, + -- module_load="value" + [2] = { + str = "^%s*([%w_]+)_load%s*=%s*\"([%w%s%p]-)\"%s*(.*)", + process = function(k, v) + if modules[k] == nil then + modules[k] = {}; + end + modules[k].load = string.upper(v); + end + }, + -- module_name="value" + [3] = { + str = "^%s*([%w_]+)_name%s*=%s*\"([%w%s%p]-)\"%s*(.*)", + process = function(k, v) + config.setKey(k, "name", v); + end + }, + -- module_type="value" + [4] = { + str = "^%s*([%w_]+)_type%s*=%s*\"([%w%s%p]-)\"%s*(.*)", + process = function(k, v) + config.setKey(k, "type", v); + end + }, + -- module_flags="value" + [5] = { + str = "^%s*([%w_]+)_flags%s*=%s*\"([%w%s%p]-)\"%s*(.*)", + process = function(k, v) + config.setKey(k, "flags", v); + end + }, + -- module_before="value" + [6] = { + str = "^%s*([%w_]+)_before%s*=%s*\"([%w%s%p]-)\"%s*(.*)", + process = function(k, v) + config.setKey(k, "before", v); + end + }, + -- module_after="value" + [7] = { + str = "^%s*([%w_]+)_after%s*=%s*\"([%w%s%p]-)\"%s*(.*)", + process = function(k, v) + config.setKey(k, "after", v); + end + }, + -- module_error="value" + [8] = { + str = "^%s*([%w_]+)_error%s*=%s*\"([%w%s%p]-)\"%s*(.*)", + process = function(k, v) + config.setKey(k, "error", v); + end + }, + -- exec="command" + [9] = { + str = "^%s*exec%s*=%s*\"([%w%s%p]-)\"%s*(.*)", + process = function(k, v) + if loader.perform(k) ~= 0 then + print("Failed to exec '"..k.."'"); + end + end + }, + -- env_var="value" + [10] = { + str = "^%s*([%w%p]+)%s*=%s*\"([%w%s%p]-)\"%s*(.*)", + process = function(k, v) + if loader.setenv(k, v) ~= 0 then + print("Failed to set '"..k.."' with value: "..v..""); + end + end + }, + -- env_var=num + [11] = { + str = "^%s*([%w%p]+)%s*=%s*(%d+)%s*(.*)", + process = function(k, v) + if loader.setenv(k, v) ~= 0 then + print("Failed to set '"..k.."' with value: "..v..""); + end + end + } +}; + +function config.isValidComment(c) + if c ~= nil then + local s = string.match(c, "^%s*#.*"); + if s == nil then + s = string.match(c, "^%s*$"); + end + if s == nil then + return false; + end + end + return true; +end + +function config.loadmod(mod, silent) + local status = true; + for k, v in pairs(mod) do + if v.load == "YES" then + local str = "load "; + if v.flags ~= nil then + str = str .. v.flags .. " "; + end + if v.type ~= nil then + str = str .. "-t " .. v.type .. " "; + end + if v.name ~= nil then + str = str .. v.name; + else + str = str .. k; + end + + if v.before ~= nil then + if loader.perform(v.before) ~= 0 then + if not silent then + print("Failed to execute '"..v.before.."' before loading '"..k.."'"); + end + status = false; + end + end + + if loader.perform(str) ~= 0 then + if not silent then + print("Failed to execute '" .. str .. "'"); + end + if v.error ~= nil then + loader.perform(v.error); + end + status = false; + end + + if v.after ~= nil then + if loader.perform(v.after) ~= 0 then + if not silent then + print("Failed to execute '"..v.after.."' after loading '"..k.."'"); + end + status = false; + end + end + + else + --if not silent then print("Skiping module '".. k .. "'"); end + end + end + + return status; +end + +function config.parse(name, silent) + local f = io.open(name); + if f == nil then + if not silent then + print("Failed to open config: '" .. name.."'"); + end + return false; + end + + local text; + local r; + + text, r = io.read(f); + + if text == nil then + if not silent then + print("Failed to read config: '" .. name.."'"); + end + return false; + end + + local n = 1; + local status = true; + + for line in string.gmatch(text, "([^\n]+)") do + + if string.match(line, "^%s*$") == nil then + local found = false; + + for i, val in ipairs(pattern_table) do + local k, v, c = string.match(line, val.str); + if k ~= nil then + found = true; + + if config.isValidComment(c) then + val.process(k, v); + else + print("Malformed line ("..n.."):\n\t'"..line.."'"); + status = false; + end + + break; + end + end + + if found == false then + print("Malformed line ("..n.."):\n\t'"..line.."'"); + status = false; + end + end + n = n + 1; + end + + return status; +end + +function config.loadkernel() + local flags = loader.getenv("kernel_options") or ""; + local kernel = loader.getenv("kernel"); + + local try_load = function (names) + for name in names:gmatch("([^;]+)%s*;?") do + r = loader.perform("load "..flags.." "..name); + if r == 0 then + return name; + end + end + return nil; + end; + + local load_bootfile = function() + local bootfile = loader.getenv("bootfile"); + + -- append default kernel name + if not bootfile then + bootfile = "kernel"; + else + bootfile = bootfile..";kernel"; + end + + return try_load(bootfile); + end; + + -- kernel not set, try load from default module_path + if kernel == nil then + local res = load_bootfile(); + + if res ~= nil then + return true; + else + print("Failed to load kernel '"..res.."'"); + return false; + end + else + local module_path = loader.getenv("module_path"); + local res = nil; + + -- first try load kernel with module_path = /boot/${kernel} + -- then try load with module_path=${kernel} + local paths = {"/boot/"..kernel, kernel}; + + for k,v in pairs(paths) do + + loader.setenv("module_path", v); + res = load_bootfile(); + + -- succeeded add path to module_path + if res ~= nil then + loader.setenv("module_path", v..";"..module_path); + return true; + end + end + + -- failed to load with ${kernel} as a directory + -- try as a file + res = try_load(kernel); + if res ~= nil then + return true; + else + print("Failed to load kernel '"..res.."'"); + return false; + end + end +end + + +function config.load(file) + + if not file then + file = "/boot/defaults/loader.conf"; + end + + if not config.parse(file) then +-- print("Failed to parse configuration: '"..file.."'"); + end + + local f = loader.getenv("loader_conf_files"); + if f ~= nil then + for name in string.gmatch(f, "([%w%p]+)%s*") do + if not config.parse(name) then +-- print("Failed to parse configuration: '"..name.."'"); + end + end + end + + print("Loading kernel..."); + config.loadkernel(); + + print("Loading configurations..."); + if not config.loadmod(modules) then + print("Could not load configurations!"); + end +end + +function config.reload(kernel) + local res = 1; + + -- unload all modules + print("Unloading modules..."); + loader.perform("unload"); + + if kernel ~= nil then + res = loader.perform("load "..kernel); + if res == 0 then + print("Kernel '"..kernel.."' loaded!"); + end + end + + -- failed to load kernel or it is nil + -- then load default + if res == 1 then + print("Loading default kernel..."); + config.loadkernel(); + end + + -- load modules + config.loadmod(modules); +end + +return config Index: stand/lua/core.lua =================================================================== --- /dev/null +++ stand/lua/core.lua @@ -0,0 +1,154 @@ +-- +-- 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 core = {}; + +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.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 i = 0; + if k ~= nil then + i = i + 1; + kernels[i] = k; + end + + for n in v:gmatch("([^; ]+)[; ]?") do + if n ~= k then + i = i + 1; + kernels[i] = n; + end + end + return kernels; +end + +function core.setDefaults() + core.setACPI(true); + core.setSafeMode(false); + core.setSingleUser(false); + core.setVerbose(false); +end + +function core.autoboot() + loader.perform("autoboot"); +end + +function core.boot() + loader.perform("boot"); +end + +function core.bootserial() + 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 + +return core Index: stand/lua/drawer.lua =================================================================== --- /dev/null +++ stand/lua/drawer.lua @@ -0,0 +1,309 @@ +-- +-- 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 drawer = {}; + +local color = require("color"); +local screen = require("screen"); + +drawer.brand_position = {x = 2, y = 1}; +drawer.fbsd_logo = { + " ______ ____ _____ _____ ", + " | ____| | _ \\ / ____| __ \\ ", + " | |___ _ __ ___ ___ | |_) | (___ | | | |", + " | ___| '__/ _ \\/ _ \\| _ < \\___ \\| | | |", + " | | | | | __/ __/| |_) |____) | |__| |", + " | | | | | | || | | |", + " |_| |_| \\___|\\___||____/|_____/|_____/ " +}; + +drawer.logo_position = {x = 46, y = 1}; +drawer.beastie_color = { + " \027[31m, ,", + " /( )`", + " \\ \\___ / |", + " /- \027[37m_\027[31m `-/ '", + " (\027[37m/\\/ \\\027[31m \\ /\\", + " \027[37m/ / |\027[31m ` \\", + " \027[34mO O \027[37m) \027[31m/ |", + " \027[37m`-^--'\027[31m`< '", + " (_.) _ ) /", + " `.___/` /", + " `-----' /", + " \027[33m<----.\027[31m __ / __ \\", + " \027[33m<----|====\027[31mO)))\027[33m==\027[31m) \\) /\027[33m====|", + " \027[33m<----'\027[31m `--' `.__,' \\", + " | |", + " \\ / /\\", + " \027[36m______\027[31m( (_ / \\______/", + " \027[36m,' ,-----' |", + " `--{__________)\027[37m" +}; + +drawer.beastie = { + " , ,", + " /( )`", + " \\ \\___ / |", + " /- _ `-/ '", + " (/\\/ \\ \\ /\\", + " / / | ` \\", + " O O ) / |", + " `-^--'`< '", + " (_.) _ ) /", + " `.___/` /", + " `-----' /", + " <----. __ / __ \\", + " <----|====O)))==) \\) /====|", + " <----' `--' `.__,' \\", + " | |", + " \\ / /\\", + " ______( (_ / \\______/", + " ,' ,-----' |", + " `--{__________)" +}; + +drawer.fbsd_logo_shift = {x = 5, y = 4}; +drawer.fbsd_logo_v = { + " ______", + " | ____| __ ___ ___ ", + " | |__ | '__/ _ \\/ _ \\", + " | __|| | | __/ __/", + " | | | | | | |", + " |_| |_| \\___|\\___|", + " ____ _____ _____", + " | _ \\ / ____| __ \\", + " | |_) | (___ | | | |", + " | _ < \\___ \\| | | |", + " | |_) |____) | |__| |", + " | | | |", + " |____/|_____/|_____/" +}; + +drawer.orb_shift = {x = 2, y = 4}; +drawer.orb_color = { + " \027[31m``` \027[31;1m`\027[31m", + " s` `.....---...\027[31;1m....--.``` -/\027[31m", + " +o .--` \027[31;1m/y:` +.\027[31m", + " yo`:. \027[31;1m:o `+-\027[31m", + " y/ \027[31;1m-/` -o/\027[31m", + " .- \027[31;1m::/sy+:.\027[31m", + " / \027[31;1m`-- /\027[31m", + " `: \027[31;1m:`\027[31m", + " `: \027[31;1m:`\027[31m", + " / \027[31;1m/\027[31m", + " .- \027[31;1m-.\027[31m", + " -- \027[31;1m-.\027[31m", + " `:` \027[31;1m`:`", + " \027[31;1m.-- `--.", + " .---.....----.\027[37m" +}; + +drawer.orb = { + " ``` `", + " s` `.....---.......--.``` -/", + " +o .--` /y:` +.", + " yo`:. :o `+-", + " y/ -/` -o/", + " .- ::/sy+:.", + " / `-- /", + " `: :`", + " `: :`", + " / /", + " .- -.", + " -- -.", + " `:` `:`", + " .-- `--.", + " .---.....----." +}; + +drawer.none = {""}; + +drawer.none_shift = {x = 17, y = 0}; + +drawer.menu_position = {x = 6, y = 11}; + +drawer.box_pos_dim = {x = 3, y = 10, w = 41, h = 11}; + +function drawer.drawscreen(menu_opts) + -- drawlogo() must go first. + -- it determines the positions of other elements + drawer.drawlogo(); + drawer.drawbrand(); + drawer.drawbox(); + return drawer.drawmenu(menu_opts); +end + +function drawer.drawmenu(m) + x = drawer.menu_position.x; + y = drawer.menu_position.y; + + -- print the menu and build the alias table + local alias_table = {}; + local entry_num = 0; + for line_num, e in ipairs(m) do + if (e.entry_type ~= "separator") then + entry_num = entry_num + 1; + screen.setcursor(x, y + line_num); + print(entry_num .. ". "..e.name()); + + -- fill the alias table + alias_table[tostring(entry_num)] = e; + for n, a in ipairs(e.alias) do + alias_table[a] = e; + end + else + screen.setcursor(x, y + line_num); + print(e.name()); + end + end + return alias_table; +end + + +function drawer.drawbox() + x = drawer.box_pos_dim.x; + y = drawer.box_pos_dim.y; + w = drawer.box_pos_dim.w; + h = drawer.box_pos_dim.h; + + local hl = string.char(0xCD); + local vl = string.char(0xBA); + + local tl = string.char(0xC9); + local bl = string.char(0xC8); + local tr = string.char(0xBB); + local br = string.char(0xBC); + + screen.setcursor(x, y); print(tl); + screen.setcursor(x, y+h); print(bl); + screen.setcursor(x+w, y); print(tr); + screen.setcursor(x+w, y+h); print(br); + + for i = 1, w-1 do + screen.setcursor(x+i, y); + print(hl); + screen.setcursor(x+i, y+h); + print(hl); + end + + for i = 1, h-1 do + screen.setcursor(x, y+i); + print(vl); + screen.setcursor(x+w, y+i); + print(vl); + end + + screen.setcursor(x+(w/2)-9, y); + print("Welcome to FreeBSD"); +end + +function drawer.draw(x, y, logo) + for i = 1, #logo do + screen.setcursor(x, y + i); + print(logo[i]); + end +end + +function drawer.drawbrand() + local x = tonumber(loader.getenv("loader_brand_x")); + local y = tonumber(loader.getenv("loader_brand_y")); + + if not x then + x = drawer.brand_position.x; + end + if not y then + y = drawer.brand_position.y; + end + + local logo = load("return " .. tostring(loader.getenv("loader_brand")))(); + if not logo then + logo = drawer.fbsd_logo; + end + drawer.draw(x, y, logo); +end + +function drawer.drawlogo() + local x = tonumber(loader.getenv("loader_logo_x")); + local y = tonumber(loader.getenv("loader_logo_y")); + + if not x then + x = drawer.logo_position.x; + end + if not y then + y = drawer.logo_position.y; + end + + local logo = loader.getenv("loader_logo"); + local s = {x = 0, y = 0}; + local colored = color.isEnabled(); + + if logo == "beastie" then + if colored then + logo = drawer.beastie_color; + end + elseif logo == "beastiebw" then + logo = drawer.beastie; + elseif logo == "fbsdbw" then + logo = drawer.fbsd_logo_v; + s = drawer.fbsd_logo_shift; + elseif logo == "orb" then + if colored then + logo = drawer.orb_color; + end + s = drawer.orb_shift; + elseif logo == "orbbw" then + logo = drawer.orb; + s = drawer.orb_shift; + elseif logo == "tribute" then + logo = drawer.fbsd_logo; + elseif logo == "tributebw" then + logo = drawer.fbsd_logo; + elseif logo == "none" then + --centre brand and text if no logo + drawer.brand_position.x = drawer.brand_position.x + drawer.none_shift.x; + drawer.brand_position.y = drawer.brand_position.y + drawer.none_shift.y; + drawer.menu_position.x = drawer.menu_position.x + drawer.none_shift.x; + drawer.menu_position.y = drawer.menu_position.y + drawer.none_shift.y; + drawer.box_pos_dim.x = drawer.box_pos_dim.x + drawer.none_shift.x; + drawer.box_pos_dim.y = drawer.box_pos_dim.y + drawer.none_shift.y; + --prevent redraws from moving menu further + drawer.none_shift.x = 0; + drawer.none_shift.y = 0; + logo = drawer.none; + end + if not logo then + if colored then + logo = drawer.orb_color; + else + logo = drawer.orb; + end + end + drawer.draw(x + s.x, y + s.y, logo); +end + +return drawer Index: stand/lua/loader.lua =================================================================== --- /dev/null +++ stand/lua/loader.lua @@ -0,0 +1,35 @@ +-- +-- 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$ +-- + +config = require("config"); +menu = require("menu"); +password = require("password"); + +config.load(); +password.check(); +menu.run(); Index: stand/lua/menu.lua =================================================================== --- /dev/null +++ stand/lua/menu.lua @@ -0,0 +1,379 @@ +-- +-- 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; + +--loader menu tree: +--rooted at menu.welcome +--submenu declarations: +local kernel_options; +local boot_options; +local welcome; + +menu.kernel_options = { + -- this table is dynamically appended to when accessed + -- return to welcome menu + { + entry_type = "return", + name = function() + return "Back to main menu"..color.highlight(" [Backspace]"); + end, + alias = {"\08"} + } +}; + +menu.boot_options = { + -- return to welcome menu + { + entry_type = "return", + name = function() + return "Back to main menu"..color.highlight(" [Backspace]"); + end, + alias = {"\08"} + }, + + -- load defaults + { + entry_type = "entry", + name = function() + return "Load System "..color.highlight("D").."efaults"; + end, + func = function() + core.setDefaults() + end, + alias = {"d", "D"} + }, + + { + entry_type = "separator", + name = function() + return ""; + end + }, + + { + entry_type = "separator", + name = function() + return "Boot Options:"; + end + }, + + -- acpi + { + entry_type = "entry", + name = function() + return OnOff(color.highlight("A").."CPI :", core.acpi); + end, + func = function() + core.setACPI(); + end, + alias = {"a", "A"} + }, + -- safe mode + { + entry_type = "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 = "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 = "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 = "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", "\013"} + }, + + -- boot single user + { + entry_type = "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 = "return", + name = function() + return color.highlight("Esc").."ape to lua interpreter"; + end, + alias = {"\027"} + }, + + -- reboot + { + entry_type = "entry", + name = function() + return color.highlight("R").."eboot"; + end, + func = function() + loader.perform("reboot"); + end, + alias = {"r", "R"} + }, + + + { + entry_type = "separator", + name = function() + return ""; + end + }, + + { + entry_type = "separator", + name = function() + return "Options:"; + end + }, + + -- kernel options + { + entry_type = "submenu", + name = function() + local kernels = core.kernelList(); + if #kernels == 0 then + return "Kernels (not available)"; + end + return color.highlight("K").."ernels"; + end, + submenu = function() + + -- dynamically build the kernel menu: + local kernels = core.kernelList(); + for k, v in ipairs(kernels) do + menu.kernel_options[#menu.kernel_options + 1] = { + entry_type = "entry", + name = function() + return v; + end, + func = function() + config.reload(v); + end, + alias = {} -- automatically enumerated + } + end + + return menu.kernel_options; + end, + alias = {"k", "K"} + }, + + -- boot options + { + entry_type = "submenu", + name = function() + return "Boot "..color.highlight("O").."ptions"; + end, + submenu = function() + return menu.boot_options; + end, + alias = {"o", "O"} + } + +}; + +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 = string.char(io.getchar()); + + -- 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 == "entry") then + -- run function + sel_entry.func(); + elseif (sel_entry.entry_type == "submenu") then + -- recurse + cont = menu.run(sel_entry.submenu()); + elseif (sel_entry.entry_type == "return") then + -- 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!"); + return false; + end + + return true; +end + +function menu.skip() + if core.bootserial() 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 == "NO" or ab == "no" 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 == 13 then + break; + else + -- prevent autoboot when escaping to interpreter + loader.setenv("autoboot_delay", "NO"); + -- 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: stand/lua/password.lua =================================================================== --- /dev/null +++ stand/lua/password.lua @@ -0,0 +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 password = {}; + +local core = require("core"); +local screen = require("screen"); + +function password.read() + local str = ""; + local n = 0; + + repeat + ch = io.getchar(); + if ch == 13 then + break; + end + + if ch == 8 then + if n > 0 then + n = n - 1; + -- loader.printc("\008 \008"); + str = string.sub(str, 1, n); + end + else + -- loader.printc("*"); + str = str .. string.char(ch); + n = n + 1; + end + until n == 16 + return str; +end + +function password.check() + screen.defcursor(); + local function compare(prompt, pwd) + if (pwd == nil) then + return; + end + while true do + loader.printc(prompt); + if (pwd == password.read()) then + break; + end + print("\n\nloader: incorrect password!\n"); + loader.delay(3*1000*1000); + end + end + + local boot_pwd = loader.getenv("bootlock_password"); + compare("Boot password: ", boot_pwd); + + local pwd = loader.getenv("password"); + if (pwd ~=nil) then + core.autoboot(); + end + compare("Password: ", pwd); +end + +return password Index: stand/lua/screen.lua =================================================================== --- /dev/null +++ stand/lua/screen.lua @@ -0,0 +1,73 @@ +-- +-- 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"); + +function screen.clear() + if core.bootserial() then + return; + end + loader.printc("\027[H\027[J"); +end + +function screen.setcursor(x, y) + if core.bootserial() then + return; + end + loader.printc("\027["..y..";"..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 + return; + end + loader.printc("\027[25;0H"); +end + +return screen