1*088b4f5fSWarner Losh-- 2*088b4f5fSWarner Losh-- Copyright (c) 2015 Pedro Souza <pedrosouza@freebsd.org> 3*088b4f5fSWarner Losh-- All rights reserved. 4*088b4f5fSWarner Losh-- 5*088b4f5fSWarner Losh-- Redistribution and use in source and binary forms, with or without 6*088b4f5fSWarner Losh-- modification, are permitted provided that the following conditions 7*088b4f5fSWarner Losh-- are met: 8*088b4f5fSWarner Losh-- 1. Redistributions of source code must retain the above copyright 9*088b4f5fSWarner Losh-- notice, this list of conditions and the following disclaimer. 10*088b4f5fSWarner Losh-- 2. Redistributions in binary form must reproduce the above copyright 11*088b4f5fSWarner Losh-- notice, this list of conditions and the following disclaimer in the 12*088b4f5fSWarner Losh-- documentation and/or other materials provided with the distribution. 13*088b4f5fSWarner Losh-- 14*088b4f5fSWarner Losh-- THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15*088b4f5fSWarner Losh-- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16*088b4f5fSWarner Losh-- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17*088b4f5fSWarner Losh-- ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18*088b4f5fSWarner Losh-- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19*088b4f5fSWarner Losh-- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20*088b4f5fSWarner Losh-- OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21*088b4f5fSWarner Losh-- HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22*088b4f5fSWarner Losh-- LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23*088b4f5fSWarner Losh-- OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24*088b4f5fSWarner Losh-- SUCH DAMAGE. 25*088b4f5fSWarner Losh-- 26*088b4f5fSWarner Losh-- $FreeBSD$ 27*088b4f5fSWarner Losh-- 28*088b4f5fSWarner Losh 29*088b4f5fSWarner Losh 30*088b4f5fSWarner Loshlocal menu = {}; 31*088b4f5fSWarner Losh 32*088b4f5fSWarner Loshlocal core = require("core"); 33*088b4f5fSWarner Loshlocal color = require("color"); 34*088b4f5fSWarner Loshlocal config = require("config"); 35*088b4f5fSWarner Loshlocal screen = require("screen"); 36*088b4f5fSWarner Loshlocal drawer = require("drawer"); 37*088b4f5fSWarner Losh 38*088b4f5fSWarner Loshlocal OnOff; 39*088b4f5fSWarner Loshlocal skip; 40*088b4f5fSWarner Loshlocal run; 41*088b4f5fSWarner Loshlocal autoboot; 42*088b4f5fSWarner Losh 43*088b4f5fSWarner Losh--loader menu tree: 44*088b4f5fSWarner Losh--rooted at menu.welcome 45*088b4f5fSWarner Losh--submenu declarations: 46*088b4f5fSWarner Loshlocal kernel_options; 47*088b4f5fSWarner Loshlocal boot_options; 48*088b4f5fSWarner Loshlocal welcome; 49*088b4f5fSWarner Losh 50*088b4f5fSWarner Loshmenu.kernel_options = { 51*088b4f5fSWarner Losh -- this table is dynamically appended to when accessed 52*088b4f5fSWarner Losh -- return to welcome menu 53*088b4f5fSWarner Losh { 54*088b4f5fSWarner Losh entry_type = "return", 55*088b4f5fSWarner Losh name = function() 56*088b4f5fSWarner Losh return "Back to main menu"..color.highlight(" [Backspace]"); 57*088b4f5fSWarner Losh end, 58*088b4f5fSWarner Losh alias = {"\08"} 59*088b4f5fSWarner Losh } 60*088b4f5fSWarner Losh}; 61*088b4f5fSWarner Losh 62*088b4f5fSWarner Loshmenu.boot_options = { 63*088b4f5fSWarner Losh -- return to welcome menu 64*088b4f5fSWarner Losh { 65*088b4f5fSWarner Losh entry_type = "return", 66*088b4f5fSWarner Losh name = function() 67*088b4f5fSWarner Losh return "Back to main menu"..color.highlight(" [Backspace]"); 68*088b4f5fSWarner Losh end, 69*088b4f5fSWarner Losh alias = {"\08"} 70*088b4f5fSWarner Losh }, 71*088b4f5fSWarner Losh 72*088b4f5fSWarner Losh -- load defaults 73*088b4f5fSWarner Losh { 74*088b4f5fSWarner Losh entry_type = "entry", 75*088b4f5fSWarner Losh name = function() 76*088b4f5fSWarner Losh return "Load System "..color.highlight("D").."efaults"; 77*088b4f5fSWarner Losh end, 78*088b4f5fSWarner Losh func = function() 79*088b4f5fSWarner Losh core.setDefaults() 80*088b4f5fSWarner Losh end, 81*088b4f5fSWarner Losh alias = {"d", "D"} 82*088b4f5fSWarner Losh }, 83*088b4f5fSWarner Losh 84*088b4f5fSWarner Losh { 85*088b4f5fSWarner Losh entry_type = "separator", 86*088b4f5fSWarner Losh name = function() 87*088b4f5fSWarner Losh return ""; 88*088b4f5fSWarner Losh end 89*088b4f5fSWarner Losh }, 90*088b4f5fSWarner Losh 91*088b4f5fSWarner Losh { 92*088b4f5fSWarner Losh entry_type = "separator", 93*088b4f5fSWarner Losh name = function() 94*088b4f5fSWarner Losh return "Boot Options:"; 95*088b4f5fSWarner Losh end 96*088b4f5fSWarner Losh }, 97*088b4f5fSWarner Losh 98*088b4f5fSWarner Losh -- acpi 99*088b4f5fSWarner Losh { 100*088b4f5fSWarner Losh entry_type = "entry", 101*088b4f5fSWarner Losh name = function() 102*088b4f5fSWarner Losh return OnOff(color.highlight("A").."CPI :", core.acpi); 103*088b4f5fSWarner Losh end, 104*088b4f5fSWarner Losh func = function() 105*088b4f5fSWarner Losh core.setACPI(); 106*088b4f5fSWarner Losh end, 107*088b4f5fSWarner Losh alias = {"a", "A"} 108*088b4f5fSWarner Losh }, 109*088b4f5fSWarner Losh -- safe mode 110*088b4f5fSWarner Losh { 111*088b4f5fSWarner Losh entry_type = "entry", 112*088b4f5fSWarner Losh name = function() 113*088b4f5fSWarner Losh return OnOff("Safe "..color.highlight("M").."ode :", core.sm); 114*088b4f5fSWarner Losh end, 115*088b4f5fSWarner Losh func = function() 116*088b4f5fSWarner Losh core.setSafeMode(); 117*088b4f5fSWarner Losh end, 118*088b4f5fSWarner Losh alias = {"m", "M"} 119*088b4f5fSWarner Losh }, 120*088b4f5fSWarner Losh -- single user 121*088b4f5fSWarner Losh { 122*088b4f5fSWarner Losh entry_type = "entry", 123*088b4f5fSWarner Losh name = function() 124*088b4f5fSWarner Losh return OnOff(color.highlight("S").."ingle user:", core.su); 125*088b4f5fSWarner Losh end, 126*088b4f5fSWarner Losh func = function() 127*088b4f5fSWarner Losh core.setSingleUser(); 128*088b4f5fSWarner Losh end, 129*088b4f5fSWarner Losh alias = {"s", "S"} 130*088b4f5fSWarner Losh }, 131*088b4f5fSWarner Losh -- verbose boot 132*088b4f5fSWarner Losh { 133*088b4f5fSWarner Losh entry_type = "entry", 134*088b4f5fSWarner Losh name = function() 135*088b4f5fSWarner Losh return OnOff(color.highlight("V").."erbose :", core.verbose); 136*088b4f5fSWarner Losh end, 137*088b4f5fSWarner Losh func = function() 138*088b4f5fSWarner Losh core.setVerbose(); 139*088b4f5fSWarner Losh end, 140*088b4f5fSWarner Losh alias = {"v", "V"} 141*088b4f5fSWarner Losh }, 142*088b4f5fSWarner Losh}; 143*088b4f5fSWarner Losh 144*088b4f5fSWarner Loshmenu.welcome = { 145*088b4f5fSWarner Losh -- boot multi user 146*088b4f5fSWarner Losh { 147*088b4f5fSWarner Losh entry_type = "entry", 148*088b4f5fSWarner Losh name = function() 149*088b4f5fSWarner Losh return color.highlight("B").."oot Multi user "..color.highlight("[Enter]"); 150*088b4f5fSWarner Losh end, 151*088b4f5fSWarner Losh func = function() 152*088b4f5fSWarner Losh core.setSingleUser(false); 153*088b4f5fSWarner Losh core.boot(); 154*088b4f5fSWarner Losh end, 155*088b4f5fSWarner Losh alias = {"b", "B", "\013"} 156*088b4f5fSWarner Losh }, 157*088b4f5fSWarner Losh 158*088b4f5fSWarner Losh -- boot single user 159*088b4f5fSWarner Losh { 160*088b4f5fSWarner Losh entry_type = "entry", 161*088b4f5fSWarner Losh name = function() 162*088b4f5fSWarner Losh return "Boot "..color.highlight("S").."ingle user"; 163*088b4f5fSWarner Losh end, 164*088b4f5fSWarner Losh func = function() 165*088b4f5fSWarner Losh core.setSingleUser(true); 166*088b4f5fSWarner Losh core.boot(); 167*088b4f5fSWarner Losh end, 168*088b4f5fSWarner Losh alias = {"s", "S"} 169*088b4f5fSWarner Losh }, 170*088b4f5fSWarner Losh 171*088b4f5fSWarner Losh -- escape to interpreter 172*088b4f5fSWarner Losh { 173*088b4f5fSWarner Losh entry_type = "return", 174*088b4f5fSWarner Losh name = function() 175*088b4f5fSWarner Losh return color.highlight("Esc").."ape to lua interpreter"; 176*088b4f5fSWarner Losh end, 177*088b4f5fSWarner Losh alias = {"\027"} 178*088b4f5fSWarner Losh }, 179*088b4f5fSWarner Losh 180*088b4f5fSWarner Losh -- reboot 181*088b4f5fSWarner Losh { 182*088b4f5fSWarner Losh entry_type = "entry", 183*088b4f5fSWarner Losh name = function() 184*088b4f5fSWarner Losh return color.highlight("R").."eboot"; 185*088b4f5fSWarner Losh end, 186*088b4f5fSWarner Losh func = function() 187*088b4f5fSWarner Losh loader.perform("reboot"); 188*088b4f5fSWarner Losh end, 189*088b4f5fSWarner Losh alias = {"r", "R"} 190*088b4f5fSWarner Losh }, 191*088b4f5fSWarner Losh 192*088b4f5fSWarner Losh 193*088b4f5fSWarner Losh { 194*088b4f5fSWarner Losh entry_type = "separator", 195*088b4f5fSWarner Losh name = function() 196*088b4f5fSWarner Losh return ""; 197*088b4f5fSWarner Losh end 198*088b4f5fSWarner Losh }, 199*088b4f5fSWarner Losh 200*088b4f5fSWarner Losh { 201*088b4f5fSWarner Losh entry_type = "separator", 202*088b4f5fSWarner Losh name = function() 203*088b4f5fSWarner Losh return "Options:"; 204*088b4f5fSWarner Losh end 205*088b4f5fSWarner Losh }, 206*088b4f5fSWarner Losh 207*088b4f5fSWarner Losh -- kernel options 208*088b4f5fSWarner Losh { 209*088b4f5fSWarner Losh entry_type = "submenu", 210*088b4f5fSWarner Losh name = function() 211*088b4f5fSWarner Losh local kernels = core.kernelList(); 212*088b4f5fSWarner Losh if #kernels == 0 then 213*088b4f5fSWarner Losh return "Kernels (not available)"; 214*088b4f5fSWarner Losh end 215*088b4f5fSWarner Losh return color.highlight("K").."ernels"; 216*088b4f5fSWarner Losh end, 217*088b4f5fSWarner Losh submenu = function() 218*088b4f5fSWarner Losh 219*088b4f5fSWarner Losh -- dynamically build the kernel menu: 220*088b4f5fSWarner Losh local kernels = core.kernelList(); 221*088b4f5fSWarner Losh for k, v in ipairs(kernels) do 222*088b4f5fSWarner Losh menu.kernel_options[#menu.kernel_options + 1] = { 223*088b4f5fSWarner Losh entry_type = "entry", 224*088b4f5fSWarner Losh name = function() 225*088b4f5fSWarner Losh return v; 226*088b4f5fSWarner Losh end, 227*088b4f5fSWarner Losh func = function() 228*088b4f5fSWarner Losh config.reload(v); 229*088b4f5fSWarner Losh end, 230*088b4f5fSWarner Losh alias = {} -- automatically enumerated 231*088b4f5fSWarner Losh } 232*088b4f5fSWarner Losh end 233*088b4f5fSWarner Losh 234*088b4f5fSWarner Losh return menu.kernel_options; 235*088b4f5fSWarner Losh end, 236*088b4f5fSWarner Losh alias = {"k", "K"} 237*088b4f5fSWarner Losh }, 238*088b4f5fSWarner Losh 239*088b4f5fSWarner Losh -- boot options 240*088b4f5fSWarner Losh { 241*088b4f5fSWarner Losh entry_type = "submenu", 242*088b4f5fSWarner Losh name = function() 243*088b4f5fSWarner Losh return "Boot "..color.highlight("O").."ptions"; 244*088b4f5fSWarner Losh end, 245*088b4f5fSWarner Losh submenu = function() 246*088b4f5fSWarner Losh return menu.boot_options; 247*088b4f5fSWarner Losh end, 248*088b4f5fSWarner Losh alias = {"o", "O"} 249*088b4f5fSWarner Losh } 250*088b4f5fSWarner Losh 251*088b4f5fSWarner Losh}; 252*088b4f5fSWarner Losh 253*088b4f5fSWarner Loshfunction menu.run(m) 254*088b4f5fSWarner Losh 255*088b4f5fSWarner Losh if (menu.skip()) then 256*088b4f5fSWarner Losh core.autoboot(); 257*088b4f5fSWarner Losh return false; 258*088b4f5fSWarner Losh end 259*088b4f5fSWarner Losh 260*088b4f5fSWarner Losh if (m == nil) then 261*088b4f5fSWarner Losh m = menu.welcome; 262*088b4f5fSWarner Losh end 263*088b4f5fSWarner Losh 264*088b4f5fSWarner Losh -- redraw screen 265*088b4f5fSWarner Losh screen.clear(); 266*088b4f5fSWarner Losh screen.defcursor(); 267*088b4f5fSWarner Losh local alias_table = drawer.drawscreen(m); 268*088b4f5fSWarner Losh 269*088b4f5fSWarner Losh-- menu.autoboot(); 270*088b4f5fSWarner Losh 271*088b4f5fSWarner Losh cont = true; 272*088b4f5fSWarner Losh while cont do 273*088b4f5fSWarner Losh local key = string.char(io.getchar()); 274*088b4f5fSWarner Losh 275*088b4f5fSWarner Losh -- check to see if key is an alias 276*088b4f5fSWarner Losh local sel_entry = nil; 277*088b4f5fSWarner Losh for k, v in pairs(alias_table) do 278*088b4f5fSWarner Losh if (key == k) then 279*088b4f5fSWarner Losh sel_entry = v; 280*088b4f5fSWarner Losh end 281*088b4f5fSWarner Losh end 282*088b4f5fSWarner Losh 283*088b4f5fSWarner Losh -- if we have an alias do the assigned action: 284*088b4f5fSWarner Losh if(sel_entry ~= nil) then 285*088b4f5fSWarner Losh if (sel_entry.entry_type == "entry") then 286*088b4f5fSWarner Losh -- run function 287*088b4f5fSWarner Losh sel_entry.func(); 288*088b4f5fSWarner Losh elseif (sel_entry.entry_type == "submenu") then 289*088b4f5fSWarner Losh -- recurse 290*088b4f5fSWarner Losh cont = menu.run(sel_entry.submenu()); 291*088b4f5fSWarner Losh elseif (sel_entry.entry_type == "return") then 292*088b4f5fSWarner Losh -- break recurse 293*088b4f5fSWarner Losh cont = false; 294*088b4f5fSWarner Losh end 295*088b4f5fSWarner Losh -- if we got an alias key the screen is out of date: 296*088b4f5fSWarner Losh screen.clear(); 297*088b4f5fSWarner Losh screen.defcursor(); 298*088b4f5fSWarner Losh alias_table = drawer.drawscreen(m); 299*088b4f5fSWarner Losh end 300*088b4f5fSWarner Losh end 301*088b4f5fSWarner Losh 302*088b4f5fSWarner Losh if (m == menu.welcome) then 303*088b4f5fSWarner Losh screen.defcursor(); 304*088b4f5fSWarner Losh print("Exiting menu!"); 305*088b4f5fSWarner Losh return false; 306*088b4f5fSWarner Losh end 307*088b4f5fSWarner Losh 308*088b4f5fSWarner Losh return true; 309*088b4f5fSWarner Loshend 310*088b4f5fSWarner Losh 311*088b4f5fSWarner Loshfunction menu.skip() 312*088b4f5fSWarner Losh if core.bootserial() then 313*088b4f5fSWarner Losh return true; 314*088b4f5fSWarner Losh end 315*088b4f5fSWarner Losh local c = string.lower(loader.getenv("console") or ""); 316*088b4f5fSWarner Losh if (c:match("^efi[ ;]") or c:match("[ ;]efi[ ;]")) ~= nil then 317*088b4f5fSWarner Losh return true; 318*088b4f5fSWarner Losh end 319*088b4f5fSWarner Losh 320*088b4f5fSWarner Losh c = string.lower(loader.getenv("beastie_disable") or ""); 321*088b4f5fSWarner Losh print("beastie_disable", c); 322*088b4f5fSWarner Losh return c == "yes"; 323*088b4f5fSWarner Loshend 324*088b4f5fSWarner Losh 325*088b4f5fSWarner Loshfunction menu.autoboot() 326*088b4f5fSWarner Losh if menu.already_autoboot == true then 327*088b4f5fSWarner Losh return; 328*088b4f5fSWarner Losh end 329*088b4f5fSWarner Losh menu.already_autoboot = true; 330*088b4f5fSWarner Losh 331*088b4f5fSWarner Losh local ab = loader.getenv("autoboot_delay"); 332*088b4f5fSWarner Losh if ab == "NO" or ab == "no" then 333*088b4f5fSWarner Losh core.boot(); 334*088b4f5fSWarner Losh end 335*088b4f5fSWarner Losh ab = tonumber(ab) or 10; 336*088b4f5fSWarner Losh 337*088b4f5fSWarner Losh local x = loader.getenv("loader_menu_timeout_x") or 5; 338*088b4f5fSWarner Losh local y = loader.getenv("loader_menu_timeout_y") or 22; 339*088b4f5fSWarner Losh 340*088b4f5fSWarner Losh local endtime = loader.time() + ab; 341*088b4f5fSWarner Losh local time; 342*088b4f5fSWarner Losh 343*088b4f5fSWarner Losh repeat 344*088b4f5fSWarner Losh time = endtime - loader.time(); 345*088b4f5fSWarner Losh screen.setcursor(x, y); 346*088b4f5fSWarner Losh print("Autoboot in "..time.." seconds, hit [Enter] to boot" 347*088b4f5fSWarner Losh .." or any other key to stop "); 348*088b4f5fSWarner Losh screen.defcursor(); 349*088b4f5fSWarner Losh if io.ischar() then 350*088b4f5fSWarner Losh local ch = io.getchar(); 351*088b4f5fSWarner Losh if ch == 13 then 352*088b4f5fSWarner Losh break; 353*088b4f5fSWarner Losh else 354*088b4f5fSWarner Losh -- prevent autoboot when escaping to interpreter 355*088b4f5fSWarner Losh loader.setenv("autoboot_delay", "NO"); 356*088b4f5fSWarner Losh -- erase autoboot msg 357*088b4f5fSWarner Losh screen.setcursor(0, y); 358*088b4f5fSWarner Losh print(" " 359*088b4f5fSWarner Losh .." "); 360*088b4f5fSWarner Losh screen.defcursor(); 361*088b4f5fSWarner Losh return; 362*088b4f5fSWarner Losh end 363*088b4f5fSWarner Losh end 364*088b4f5fSWarner Losh 365*088b4f5fSWarner Losh loader.delay(50000); 366*088b4f5fSWarner Losh until time <= 0 367*088b4f5fSWarner Losh core.boot(); 368*088b4f5fSWarner Losh 369*088b4f5fSWarner Loshend 370*088b4f5fSWarner Losh 371*088b4f5fSWarner Loshfunction OnOff(str, b) 372*088b4f5fSWarner Losh if (b) then 373*088b4f5fSWarner Losh return str .. color.escapef(color.GREEN).."On"..color.escapef(color.WHITE); 374*088b4f5fSWarner Losh else 375*088b4f5fSWarner Losh return str .. color.escapef(color.RED).."off"..color.escapef(color.WHITE); 376*088b4f5fSWarner Losh end 377*088b4f5fSWarner Loshend 378*088b4f5fSWarner Losh 379*088b4f5fSWarner Loshreturn menu 380