1088b4f5fSWarner Losh-- 2088b4f5fSWarner Losh-- Copyright (c) 2015 Pedro Souza <pedrosouza@freebsd.org> 3088b4f5fSWarner Losh-- All rights reserved. 4088b4f5fSWarner Losh-- 5088b4f5fSWarner Losh-- Redistribution and use in source and binary forms, with or without 6088b4f5fSWarner Losh-- modification, are permitted provided that the following conditions 7088b4f5fSWarner Losh-- are met: 8088b4f5fSWarner Losh-- 1. Redistributions of source code must retain the above copyright 9088b4f5fSWarner Losh-- notice, this list of conditions and the following disclaimer. 10088b4f5fSWarner Losh-- 2. Redistributions in binary form must reproduce the above copyright 11088b4f5fSWarner Losh-- notice, this list of conditions and the following disclaimer in the 12088b4f5fSWarner Losh-- documentation and/or other materials provided with the distribution. 13088b4f5fSWarner Losh-- 14088b4f5fSWarner Losh-- THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15088b4f5fSWarner Losh-- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16088b4f5fSWarner Losh-- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17088b4f5fSWarner Losh-- ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18088b4f5fSWarner Losh-- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19088b4f5fSWarner Losh-- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20088b4f5fSWarner Losh-- OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21088b4f5fSWarner Losh-- HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22088b4f5fSWarner Losh-- LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23088b4f5fSWarner Losh-- OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24088b4f5fSWarner Losh-- SUCH DAMAGE. 25088b4f5fSWarner Losh-- 26088b4f5fSWarner Losh-- $FreeBSD$ 27088b4f5fSWarner Losh-- 28088b4f5fSWarner Losh 29088b4f5fSWarner Losh 30088b4f5fSWarner Loshlocal menu = {}; 31088b4f5fSWarner Losh 32088b4f5fSWarner Loshlocal core = require("core"); 33088b4f5fSWarner Loshlocal color = require("color"); 34088b4f5fSWarner Loshlocal config = require("config"); 35088b4f5fSWarner Loshlocal screen = require("screen"); 36088b4f5fSWarner Loshlocal drawer = require("drawer"); 37088b4f5fSWarner Losh 38088b4f5fSWarner Loshlocal OnOff; 39088b4f5fSWarner Loshlocal skip; 40088b4f5fSWarner Loshlocal run; 41088b4f5fSWarner Loshlocal autoboot; 42ada26c4aSKyle Evanslocal carousel_choices = {}; 43088b4f5fSWarner Losh 44088b4f5fSWarner Losh--loader menu tree: 45088b4f5fSWarner Losh--rooted at menu.welcome 46088b4f5fSWarner Losh--submenu declarations: 47088b4f5fSWarner Loshlocal boot_options; 48088b4f5fSWarner Loshlocal welcome; 49088b4f5fSWarner Losh 50088b4f5fSWarner Loshmenu.boot_options = { 51088b4f5fSWarner Losh -- return to welcome menu 52088b4f5fSWarner Losh { 53a7cf0562SKyle Evans entry_type = core.MENU_RETURN, 54088b4f5fSWarner Losh name = function() 55*57099121SKyle Evans return "Back to main menu" .. 56*57099121SKyle Evans color.highlight(" [Backspace]"); 571666dfc0SKyle Evans end 58088b4f5fSWarner Losh }, 59088b4f5fSWarner Losh 60088b4f5fSWarner Losh -- load defaults 61088b4f5fSWarner Losh { 62a7cf0562SKyle Evans entry_type = core.MENU_ENTRY, 63088b4f5fSWarner Losh name = function() 64*57099121SKyle Evans return "Load System " .. color.highlight("D") .. 65*57099121SKyle Evans "efaults"; 66088b4f5fSWarner Losh end, 67088b4f5fSWarner Losh func = function() 6824a1bd54SKyle Evans core.setDefaults(); 69088b4f5fSWarner Losh end, 70088b4f5fSWarner Losh alias = {"d", "D"} 71088b4f5fSWarner Losh }, 72088b4f5fSWarner Losh 73088b4f5fSWarner Losh { 74a7cf0562SKyle Evans entry_type = core.MENU_SEPARATOR, 75088b4f5fSWarner Losh name = function() 76088b4f5fSWarner Losh return ""; 77088b4f5fSWarner Losh end 78088b4f5fSWarner Losh }, 79088b4f5fSWarner Losh 80088b4f5fSWarner Losh { 81a7cf0562SKyle Evans entry_type = core.MENU_SEPARATOR, 82088b4f5fSWarner Losh name = function() 83088b4f5fSWarner Losh return "Boot Options:"; 84088b4f5fSWarner Losh end 85088b4f5fSWarner Losh }, 86088b4f5fSWarner Losh 87088b4f5fSWarner Losh -- acpi 88088b4f5fSWarner Losh { 89a7cf0562SKyle Evans entry_type = core.MENU_ENTRY, 90088b4f5fSWarner Losh name = function() 91*57099121SKyle Evans return OnOff(color.highlight("A") .. "CPI :", 92*57099121SKyle Evans core.acpi); 93088b4f5fSWarner Losh end, 94088b4f5fSWarner Losh func = function() 95088b4f5fSWarner Losh core.setACPI(); 96088b4f5fSWarner Losh end, 97088b4f5fSWarner Losh alias = {"a", "A"} 98088b4f5fSWarner Losh }, 99088b4f5fSWarner Losh -- safe mode 100088b4f5fSWarner Losh { 101a7cf0562SKyle Evans entry_type = core.MENU_ENTRY, 102088b4f5fSWarner Losh name = function() 103*57099121SKyle Evans return OnOff("Safe " .. color.highlight("M") .. 104*57099121SKyle Evans "ode :", core.sm); 105088b4f5fSWarner Losh end, 106088b4f5fSWarner Losh func = function() 107088b4f5fSWarner Losh core.setSafeMode(); 108088b4f5fSWarner Losh end, 109088b4f5fSWarner Losh alias = {"m", "M"} 110088b4f5fSWarner Losh }, 111088b4f5fSWarner Losh -- single user 112088b4f5fSWarner Losh { 113a7cf0562SKyle Evans entry_type = core.MENU_ENTRY, 114088b4f5fSWarner Losh name = function() 115*57099121SKyle Evans return OnOff(color.highlight("S") .. "ingle user:", 116*57099121SKyle Evans core.su); 117088b4f5fSWarner Losh end, 118088b4f5fSWarner Losh func = function() 119088b4f5fSWarner Losh core.setSingleUser(); 120088b4f5fSWarner Losh end, 121088b4f5fSWarner Losh alias = {"s", "S"} 122088b4f5fSWarner Losh }, 123088b4f5fSWarner Losh -- verbose boot 124088b4f5fSWarner Losh { 125a7cf0562SKyle Evans entry_type = core.MENU_ENTRY, 126088b4f5fSWarner Losh name = function() 127*57099121SKyle Evans return OnOff(color.highlight("V") .. "erbose :", 128*57099121SKyle Evans core.verbose); 129088b4f5fSWarner Losh end, 130088b4f5fSWarner Losh func = function() 131088b4f5fSWarner Losh core.setVerbose(); 132088b4f5fSWarner Losh end, 133088b4f5fSWarner Losh alias = {"v", "V"} 134088b4f5fSWarner Losh }, 135088b4f5fSWarner Losh}; 136088b4f5fSWarner Losh 137088b4f5fSWarner Loshmenu.welcome = { 138088b4f5fSWarner Losh -- boot multi user 139088b4f5fSWarner Losh { 140a7cf0562SKyle Evans entry_type = core.MENU_ENTRY, 141088b4f5fSWarner Losh name = function() 142*57099121SKyle Evans return color.highlight("B") .. "oot Multi user " .. 143*57099121SKyle Evans color.highlight("[Enter]"); 144088b4f5fSWarner Losh end, 145088b4f5fSWarner Losh func = function() 146088b4f5fSWarner Losh core.setSingleUser(false); 147088b4f5fSWarner Losh core.boot(); 148088b4f5fSWarner Losh end, 149b458bf0dSKyle Evans alias = {"b", "B"} 150088b4f5fSWarner Losh }, 151088b4f5fSWarner Losh 152088b4f5fSWarner Losh -- boot single user 153088b4f5fSWarner Losh { 154a7cf0562SKyle Evans entry_type = core.MENU_ENTRY, 155088b4f5fSWarner Losh name = function() 156088b4f5fSWarner Losh return "Boot " .. color.highlight("S") .. "ingle user"; 157088b4f5fSWarner Losh end, 158088b4f5fSWarner Losh func = function() 159088b4f5fSWarner Losh core.setSingleUser(true); 160088b4f5fSWarner Losh core.boot(); 161088b4f5fSWarner Losh end, 162088b4f5fSWarner Losh alias = {"s", "S"} 163088b4f5fSWarner Losh }, 164088b4f5fSWarner Losh 165088b4f5fSWarner Losh -- escape to interpreter 166088b4f5fSWarner Losh { 167a7cf0562SKyle Evans entry_type = core.MENU_RETURN, 168088b4f5fSWarner Losh name = function() 169e9084012SKyle Evans return color.highlight("Esc") .. "ape to loader prompt"; 170088b4f5fSWarner Losh end, 171ef625845SKyle Evans func = function() 17224a1bd54SKyle Evans loader.setenv("autoboot_delay", "NO"); 173ef625845SKyle Evans end, 17439006570SKyle Evans alias = {core.KEYSTR_ESCAPE} 175088b4f5fSWarner Losh }, 176088b4f5fSWarner Losh 177088b4f5fSWarner Losh -- reboot 178088b4f5fSWarner Losh { 179a7cf0562SKyle Evans entry_type = core.MENU_ENTRY, 180088b4f5fSWarner Losh name = function() 181088b4f5fSWarner Losh return color.highlight("R") .. "eboot"; 182088b4f5fSWarner Losh end, 183088b4f5fSWarner Losh func = function() 184088b4f5fSWarner Losh loader.perform("reboot"); 185088b4f5fSWarner Losh end, 186088b4f5fSWarner Losh alias = {"r", "R"} 187088b4f5fSWarner Losh }, 188088b4f5fSWarner Losh 189088b4f5fSWarner Losh 190088b4f5fSWarner Losh { 191a7cf0562SKyle Evans entry_type = core.MENU_SEPARATOR, 192088b4f5fSWarner Losh name = function() 193088b4f5fSWarner Losh return ""; 194088b4f5fSWarner Losh end 195088b4f5fSWarner Losh }, 196088b4f5fSWarner Losh 197088b4f5fSWarner Losh { 198a7cf0562SKyle Evans entry_type = core.MENU_SEPARATOR, 199088b4f5fSWarner Losh name = function() 200088b4f5fSWarner Losh return "Options:"; 201088b4f5fSWarner Losh end 202088b4f5fSWarner Losh }, 203088b4f5fSWarner Losh 204088b4f5fSWarner Losh -- kernel options 205088b4f5fSWarner Losh { 206a7cf0562SKyle Evans entry_type = core.MENU_CAROUSEL_ENTRY, 207ada26c4aSKyle Evans carousel_id = "kernel", 208ada26c4aSKyle Evans items = core.kernelList, 209ada26c4aSKyle Evans name = function(idx, choice, all_choices) 21024a1bd54SKyle Evans if (#all_choices == 0) then 211b1b1f2b8SKyle Evans return "Kernel: "; 212088b4f5fSWarner Losh end 213b1b1f2b8SKyle Evans 214bcf48a15SKyle Evans local is_default = (idx == 1); 215bcf48a15SKyle Evans local kernel_name = ""; 216bcf48a15SKyle Evans local name_color; 21724a1bd54SKyle Evans if (is_default) then 218bcf48a15SKyle Evans name_color = color.escapef(color.GREEN); 219bcf48a15SKyle Evans kernel_name = "default/"; 220bcf48a15SKyle Evans else 221bcf48a15SKyle Evans name_color = color.escapef(color.BLUE); 222b1b1f2b8SKyle Evans end 223bcf48a15SKyle Evans kernel_name = kernel_name .. name_color .. choice .. 224bcf48a15SKyle Evans color.default(); 225b1b1f2b8SKyle Evans return color.highlight("K").."ernel: " .. kernel_name .. 226ada26c4aSKyle Evans " (" .. idx .. 227ada26c4aSKyle Evans " of " .. #all_choices .. ")"; 228088b4f5fSWarner Losh end, 2295d1e2f83SKyle Evans func = function(idx, choice, all_choices) 230fa4a2394SKyle Evans config.selectkernel(choice); 231088b4f5fSWarner Losh end, 232088b4f5fSWarner Losh alias = {"k", "K"} 233088b4f5fSWarner Losh }, 234088b4f5fSWarner Losh 235088b4f5fSWarner Losh -- boot options 236088b4f5fSWarner Losh { 237a7cf0562SKyle Evans entry_type = core.MENU_SUBMENU, 238088b4f5fSWarner Losh name = function() 239088b4f5fSWarner Losh return "Boot " .. color.highlight("O") .. "ptions"; 240088b4f5fSWarner Losh end, 241088b4f5fSWarner Losh submenu = function() 242088b4f5fSWarner Losh return menu.boot_options; 243088b4f5fSWarner Losh end, 244088b4f5fSWarner Losh alias = {"o", "O"} 245088b4f5fSWarner Losh } 246088b4f5fSWarner Losh 247088b4f5fSWarner Losh}; 248088b4f5fSWarner Losh 249ada26c4aSKyle Evans-- The first item in every carousel is always the default item. 250ada26c4aSKyle Evansfunction menu.getCarouselIndex(id) 251ada26c4aSKyle Evans local val = carousel_choices[id]; 252ada26c4aSKyle Evans if (val == nil) then 253ada26c4aSKyle Evans return 1; 254ada26c4aSKyle Evans end 255ada26c4aSKyle Evans return val; 256ada26c4aSKyle Evansend 257ada26c4aSKyle Evans 258ada26c4aSKyle Evansfunction menu.setCarouselIndex(id, idx) 259ada26c4aSKyle Evans carousel_choices[id] = idx; 260ada26c4aSKyle Evansend 261ada26c4aSKyle Evans 262088b4f5fSWarner Loshfunction menu.run(m) 263088b4f5fSWarner Losh 264088b4f5fSWarner Losh if (menu.skip()) then 265088b4f5fSWarner Losh core.autoboot(); 266088b4f5fSWarner Losh return false; 267088b4f5fSWarner Losh end 268088b4f5fSWarner Losh 269088b4f5fSWarner Losh if (m == nil) then 270088b4f5fSWarner Losh m = menu.welcome; 271088b4f5fSWarner Losh end 272088b4f5fSWarner Losh 273088b4f5fSWarner Losh -- redraw screen 274088b4f5fSWarner Losh screen.clear(); 275088b4f5fSWarner Losh screen.defcursor(); 276088b4f5fSWarner Losh local alias_table = drawer.drawscreen(m); 277088b4f5fSWarner Losh 2783a0a07d0SKyle Evans menu.autoboot(); 279088b4f5fSWarner Losh 280088b4f5fSWarner Losh cont = true; 28124a1bd54SKyle Evans while (cont) do 282abc4f7e7SKyle Evans local key = io.getchar(); 283088b4f5fSWarner Losh 284b458bf0dSKyle Evans -- Special key behaviors 2851504bce3SKyle Evans if ((key == core.KEY_BACKSPACE) or (key == core.KEY_DELETE)) and 2861504bce3SKyle Evans (m ~= menu.welcome) then 287abc4f7e7SKyle Evans break 288fe672a15SKyle Evans elseif (key == core.KEY_ENTER) then 289b458bf0dSKyle Evans core.boot(); 290b458bf0dSKyle Evans -- Should not return 291abc4f7e7SKyle Evans end 292abc4f7e7SKyle Evans 293abc4f7e7SKyle Evans key = string.char(key) 294088b4f5fSWarner Losh -- check to see if key is an alias 295088b4f5fSWarner Losh local sel_entry = nil; 296088b4f5fSWarner Losh for k, v in pairs(alias_table) do 297088b4f5fSWarner Losh if (key == k) then 298088b4f5fSWarner Losh sel_entry = v; 299088b4f5fSWarner Losh end 300088b4f5fSWarner Losh end 301088b4f5fSWarner Losh 302088b4f5fSWarner Losh -- if we have an alias do the assigned action: 303088b4f5fSWarner Losh if (sel_entry ~= nil) then 304a7cf0562SKyle Evans if (sel_entry.entry_type == core.MENU_ENTRY) then 305088b4f5fSWarner Losh -- run function 306088b4f5fSWarner Losh sel_entry.func(); 307a7cf0562SKyle Evans elseif (sel_entry.entry_type == core.MENU_CAROUSEL_ENTRY) then 308ada26c4aSKyle Evans -- carousel (rotating) functionality 309ada26c4aSKyle Evans local carid = sel_entry.carousel_id; 310ada26c4aSKyle Evans local caridx = menu.getCarouselIndex(carid); 311ada26c4aSKyle Evans local choices = sel_entry.items(); 312ada26c4aSKyle Evans 313aefcaa7eSKyle Evans if (#choices > 0) then 314ada26c4aSKyle Evans caridx = (caridx % #choices) + 1; 315ada26c4aSKyle Evans menu.setCarouselIndex(carid, caridx); 3165d1e2f83SKyle Evans sel_entry.func(caridx, choices[caridx], 31784f82e46SKyle Evans choices); 318aefcaa7eSKyle Evans end 319a7cf0562SKyle Evans elseif (sel_entry.entry_type == core.MENU_SUBMENU) then 320088b4f5fSWarner Losh -- recurse 321088b4f5fSWarner Losh cont = menu.run(sel_entry.submenu()); 322a7cf0562SKyle Evans elseif (sel_entry.entry_type == core.MENU_RETURN) then 323ef625845SKyle Evans -- allow entry to have a function/side effect 324ef625845SKyle Evans if (sel_entry.func ~= nil) then 325ef625845SKyle Evans sel_entry.func(); 326ef625845SKyle Evans end 327088b4f5fSWarner Losh -- break recurse 328088b4f5fSWarner Losh cont = false; 329088b4f5fSWarner Losh end 330088b4f5fSWarner Losh -- if we got an alias key the screen is out of date: 331088b4f5fSWarner Losh screen.clear(); 332088b4f5fSWarner Losh screen.defcursor(); 333088b4f5fSWarner Losh alias_table = drawer.drawscreen(m); 334088b4f5fSWarner Losh end 335088b4f5fSWarner Losh end 336088b4f5fSWarner Losh 337088b4f5fSWarner Losh if (m == menu.welcome) then 338088b4f5fSWarner Losh screen.defcursor(); 339088b4f5fSWarner Losh print("Exiting menu!"); 340fa4a2394SKyle Evans config.loadelf(); 341088b4f5fSWarner Losh return false; 342088b4f5fSWarner Losh end 343088b4f5fSWarner Losh 344088b4f5fSWarner Losh return true; 345088b4f5fSWarner Loshend 346088b4f5fSWarner Losh 347088b4f5fSWarner Loshfunction menu.skip() 348b140d14bSKyle Evans if (core.isSerialBoot()) then 349088b4f5fSWarner Losh return true; 350088b4f5fSWarner Losh end 351088b4f5fSWarner Losh local c = string.lower(loader.getenv("console") or ""); 35224a1bd54SKyle Evans if ((c:match("^efi[ ;]") or c:match("[ ;]efi[ ;]")) ~= nil) then 353088b4f5fSWarner Losh return true; 354088b4f5fSWarner Losh end 355088b4f5fSWarner Losh 356088b4f5fSWarner Losh c = string.lower(loader.getenv("beastie_disable") or ""); 357088b4f5fSWarner Losh print("beastie_disable", c); 358088b4f5fSWarner Losh return c == "yes"; 359088b4f5fSWarner Loshend 360088b4f5fSWarner Losh 361088b4f5fSWarner Loshfunction menu.autoboot() 36224a1bd54SKyle Evans if (menu.already_autoboot == true) then 363088b4f5fSWarner Losh return; 364088b4f5fSWarner Losh end 365088b4f5fSWarner Losh menu.already_autoboot = true; 366088b4f5fSWarner Losh 367088b4f5fSWarner Losh local ab = loader.getenv("autoboot_delay"); 368702b460dSKyle Evans if (ab ~= nil) and (ab:lower() == "no") then 369702b460dSKyle Evans return; 370702b460dSKyle Evans elseif (tonumber(ab) == -1) then 371088b4f5fSWarner Losh core.boot(); 372088b4f5fSWarner Losh end 373088b4f5fSWarner Losh ab = tonumber(ab) or 10; 374088b4f5fSWarner Losh 375088b4f5fSWarner Losh local x = loader.getenv("loader_menu_timeout_x") or 5; 376088b4f5fSWarner Losh local y = loader.getenv("loader_menu_timeout_y") or 22; 377088b4f5fSWarner Losh 378088b4f5fSWarner Losh local endtime = loader.time() + ab; 379088b4f5fSWarner Losh local time; 380088b4f5fSWarner Losh 381088b4f5fSWarner Losh repeat 382088b4f5fSWarner Losh time = endtime - loader.time(); 383088b4f5fSWarner Losh screen.setcursor(x, y); 384*57099121SKyle Evans print("Autoboot in " .. time .. 385*57099121SKyle Evans " seconds, hit [Enter] to boot" .. 386*57099121SKyle Evans " or any other key to stop "); 387088b4f5fSWarner Losh screen.defcursor(); 38824a1bd54SKyle Evans if (io.ischar()) then 389088b4f5fSWarner Losh local ch = io.getchar(); 39024a1bd54SKyle Evans if (ch == core.KEY_ENTER) then 391088b4f5fSWarner Losh break; 392088b4f5fSWarner Losh else 393088b4f5fSWarner Losh -- erase autoboot msg 394088b4f5fSWarner Losh screen.setcursor(0, y); 395088b4f5fSWarner Losh print(" " 396088b4f5fSWarner Losh .. " "); 397088b4f5fSWarner Losh screen.defcursor(); 398088b4f5fSWarner Losh return; 399088b4f5fSWarner Losh end 400088b4f5fSWarner Losh end 401088b4f5fSWarner Losh 402088b4f5fSWarner Losh loader.delay(50000); 403088b4f5fSWarner Losh until time <= 0 404088b4f5fSWarner Losh core.boot(); 405088b4f5fSWarner Losh 406088b4f5fSWarner Loshend 407088b4f5fSWarner Losh 408088b4f5fSWarner Loshfunction OnOff(str, b) 409088b4f5fSWarner Losh if (b) then 410*57099121SKyle Evans return str .. color.escapef(color.GREEN) .. "On" .. 411*57099121SKyle Evans color.escapef(color.WHITE); 412088b4f5fSWarner Losh else 413*57099121SKyle Evans return str .. color.escapef(color.RED) .. "off" .. 414*57099121SKyle Evans color.escapef(color.WHITE); 415088b4f5fSWarner Losh end 416088b4f5fSWarner Loshend 417088b4f5fSWarner Losh 41824a1bd54SKyle Evansreturn menu; 419