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() 55088b4f5fSWarner Losh return "Back to main menu"..color.highlight(" [Backspace]"); 561666dfc0SKyle Evans end 57088b4f5fSWarner Losh }, 58088b4f5fSWarner Losh 59088b4f5fSWarner Losh -- load defaults 60088b4f5fSWarner Losh { 61a7cf0562SKyle Evans entry_type = core.MENU_ENTRY, 62088b4f5fSWarner Losh name = function() 63088b4f5fSWarner Losh return "Load System "..color.highlight("D").."efaults"; 64088b4f5fSWarner Losh end, 65088b4f5fSWarner Losh func = function() 66088b4f5fSWarner Losh core.setDefaults() 67088b4f5fSWarner Losh end, 68088b4f5fSWarner Losh alias = {"d", "D"} 69088b4f5fSWarner Losh }, 70088b4f5fSWarner Losh 71088b4f5fSWarner Losh { 72a7cf0562SKyle Evans entry_type = core.MENU_SEPARATOR, 73088b4f5fSWarner Losh name = function() 74088b4f5fSWarner Losh return ""; 75088b4f5fSWarner Losh end 76088b4f5fSWarner Losh }, 77088b4f5fSWarner Losh 78088b4f5fSWarner Losh { 79a7cf0562SKyle Evans entry_type = core.MENU_SEPARATOR, 80088b4f5fSWarner Losh name = function() 81088b4f5fSWarner Losh return "Boot Options:"; 82088b4f5fSWarner Losh end 83088b4f5fSWarner Losh }, 84088b4f5fSWarner Losh 85088b4f5fSWarner Losh -- acpi 86088b4f5fSWarner Losh { 87a7cf0562SKyle Evans entry_type = core.MENU_ENTRY, 88088b4f5fSWarner Losh name = function() 89088b4f5fSWarner Losh return OnOff(color.highlight("A").."CPI :", core.acpi); 90088b4f5fSWarner Losh end, 91088b4f5fSWarner Losh func = function() 92088b4f5fSWarner Losh core.setACPI(); 93088b4f5fSWarner Losh end, 94088b4f5fSWarner Losh alias = {"a", "A"} 95088b4f5fSWarner Losh }, 96088b4f5fSWarner Losh -- safe mode 97088b4f5fSWarner Losh { 98a7cf0562SKyle Evans entry_type = core.MENU_ENTRY, 99088b4f5fSWarner Losh name = function() 100088b4f5fSWarner Losh return OnOff("Safe "..color.highlight("M").."ode :", core.sm); 101088b4f5fSWarner Losh end, 102088b4f5fSWarner Losh func = function() 103088b4f5fSWarner Losh core.setSafeMode(); 104088b4f5fSWarner Losh end, 105088b4f5fSWarner Losh alias = {"m", "M"} 106088b4f5fSWarner Losh }, 107088b4f5fSWarner Losh -- single user 108088b4f5fSWarner Losh { 109a7cf0562SKyle Evans entry_type = core.MENU_ENTRY, 110088b4f5fSWarner Losh name = function() 111088b4f5fSWarner Losh return OnOff(color.highlight("S").."ingle user:", core.su); 112088b4f5fSWarner Losh end, 113088b4f5fSWarner Losh func = function() 114088b4f5fSWarner Losh core.setSingleUser(); 115088b4f5fSWarner Losh end, 116088b4f5fSWarner Losh alias = {"s", "S"} 117088b4f5fSWarner Losh }, 118088b4f5fSWarner Losh -- verbose boot 119088b4f5fSWarner Losh { 120a7cf0562SKyle Evans entry_type = core.MENU_ENTRY, 121088b4f5fSWarner Losh name = function() 122088b4f5fSWarner Losh return OnOff(color.highlight("V").."erbose :", core.verbose); 123088b4f5fSWarner Losh end, 124088b4f5fSWarner Losh func = function() 125088b4f5fSWarner Losh core.setVerbose(); 126088b4f5fSWarner Losh end, 127088b4f5fSWarner Losh alias = {"v", "V"} 128088b4f5fSWarner Losh }, 129088b4f5fSWarner Losh}; 130088b4f5fSWarner Losh 131088b4f5fSWarner Loshmenu.welcome = { 132088b4f5fSWarner Losh -- boot multi user 133088b4f5fSWarner Losh { 134a7cf0562SKyle Evans entry_type = core.MENU_ENTRY, 135088b4f5fSWarner Losh name = function() 136088b4f5fSWarner Losh return color.highlight("B").."oot Multi user "..color.highlight("[Enter]"); 137088b4f5fSWarner Losh end, 138088b4f5fSWarner Losh func = function() 139088b4f5fSWarner Losh core.setSingleUser(false); 140088b4f5fSWarner Losh core.boot(); 141088b4f5fSWarner Losh end, 142b458bf0dSKyle Evans alias = {"b", "B"} 143088b4f5fSWarner Losh }, 144088b4f5fSWarner Losh 145088b4f5fSWarner Losh -- boot single user 146088b4f5fSWarner Losh { 147a7cf0562SKyle Evans entry_type = core.MENU_ENTRY, 148088b4f5fSWarner Losh name = function() 149088b4f5fSWarner Losh return "Boot "..color.highlight("S").."ingle user"; 150088b4f5fSWarner Losh end, 151088b4f5fSWarner Losh func = function() 152088b4f5fSWarner Losh core.setSingleUser(true); 153088b4f5fSWarner Losh core.boot(); 154088b4f5fSWarner Losh end, 155088b4f5fSWarner Losh alias = {"s", "S"} 156088b4f5fSWarner Losh }, 157088b4f5fSWarner Losh 158088b4f5fSWarner Losh -- escape to interpreter 159088b4f5fSWarner Losh { 160a7cf0562SKyle Evans entry_type = core.MENU_RETURN, 161088b4f5fSWarner Losh name = function() 162e9084012SKyle Evans return color.highlight("Esc").."ape to loader prompt"; 163088b4f5fSWarner Losh end, 164ef625845SKyle Evans func = function() 165ef625845SKyle Evans loader.setenv("autoboot_delay", "NO") 166ef625845SKyle Evans end, 16739006570SKyle Evans alias = {core.KEYSTR_ESCAPE} 168088b4f5fSWarner Losh }, 169088b4f5fSWarner Losh 170088b4f5fSWarner Losh -- reboot 171088b4f5fSWarner Losh { 172a7cf0562SKyle Evans entry_type = core.MENU_ENTRY, 173088b4f5fSWarner Losh name = function() 174088b4f5fSWarner Losh return color.highlight("R").."eboot"; 175088b4f5fSWarner Losh end, 176088b4f5fSWarner Losh func = function() 177088b4f5fSWarner Losh loader.perform("reboot"); 178088b4f5fSWarner Losh end, 179088b4f5fSWarner Losh alias = {"r", "R"} 180088b4f5fSWarner Losh }, 181088b4f5fSWarner Losh 182088b4f5fSWarner Losh 183088b4f5fSWarner Losh { 184a7cf0562SKyle Evans entry_type = core.MENU_SEPARATOR, 185088b4f5fSWarner Losh name = function() 186088b4f5fSWarner Losh return ""; 187088b4f5fSWarner Losh end 188088b4f5fSWarner Losh }, 189088b4f5fSWarner Losh 190088b4f5fSWarner Losh { 191a7cf0562SKyle Evans entry_type = core.MENU_SEPARATOR, 192088b4f5fSWarner Losh name = function() 193088b4f5fSWarner Losh return "Options:"; 194088b4f5fSWarner Losh end 195088b4f5fSWarner Losh }, 196088b4f5fSWarner Losh 197088b4f5fSWarner Losh -- kernel options 198088b4f5fSWarner Losh { 199a7cf0562SKyle Evans entry_type = core.MENU_CAROUSEL_ENTRY, 200ada26c4aSKyle Evans carousel_id = "kernel", 201ada26c4aSKyle Evans items = core.kernelList, 202ada26c4aSKyle Evans name = function(idx, choice, all_choices) 203ada26c4aSKyle Evans if #all_choices == 0 then 204b1b1f2b8SKyle Evans return "Kernel: "; 205088b4f5fSWarner Losh end 206b1b1f2b8SKyle Evans 207b1b1f2b8SKyle Evans local kernel_name = color.escapef(color.GREEN) .. 208ada26c4aSKyle Evans choice .. color.default(); 209ada26c4aSKyle Evans if (idx == 1) then 210b1b1f2b8SKyle Evans kernel_name = "default/" .. kernel_name; 211b1b1f2b8SKyle Evans end 212b1b1f2b8SKyle Evans return color.highlight("K").."ernel: " .. kernel_name .. 213ada26c4aSKyle Evans " (" .. idx .. 214ada26c4aSKyle Evans " of " .. #all_choices .. ")"; 215088b4f5fSWarner Losh end, 216*5d1e2f83SKyle Evans func = function(idx, choice, all_choices) 21784f82e46SKyle Evans if (#all_choices > 1) then 218ada26c4aSKyle Evans config.reload(choice); 21984f82e46SKyle Evans end 220088b4f5fSWarner Losh end, 221088b4f5fSWarner Losh alias = {"k", "K"} 222088b4f5fSWarner Losh }, 223088b4f5fSWarner Losh 224088b4f5fSWarner Losh -- boot options 225088b4f5fSWarner Losh { 226a7cf0562SKyle Evans entry_type = core.MENU_SUBMENU, 227088b4f5fSWarner Losh name = function() 228088b4f5fSWarner Losh return "Boot "..color.highlight("O").."ptions"; 229088b4f5fSWarner Losh end, 230088b4f5fSWarner Losh submenu = function() 231088b4f5fSWarner Losh return menu.boot_options; 232088b4f5fSWarner Losh end, 233088b4f5fSWarner Losh alias = {"o", "O"} 234088b4f5fSWarner Losh } 235088b4f5fSWarner Losh 236088b4f5fSWarner Losh}; 237088b4f5fSWarner Losh 238ada26c4aSKyle Evans-- The first item in every carousel is always the default item. 239ada26c4aSKyle Evansfunction menu.getCarouselIndex(id) 240ada26c4aSKyle Evans local val = carousel_choices[id]; 241ada26c4aSKyle Evans if (val == nil) then 242ada26c4aSKyle Evans return 1; 243ada26c4aSKyle Evans end 244ada26c4aSKyle Evans return val; 245ada26c4aSKyle Evansend 246ada26c4aSKyle Evans 247ada26c4aSKyle Evansfunction menu.setCarouselIndex(id, idx) 248ada26c4aSKyle Evans carousel_choices[id] = idx; 249ada26c4aSKyle Evansend 250ada26c4aSKyle Evans 251088b4f5fSWarner Loshfunction menu.run(m) 252088b4f5fSWarner Losh 253088b4f5fSWarner Losh if (menu.skip()) then 254088b4f5fSWarner Losh core.autoboot(); 255088b4f5fSWarner Losh return false; 256088b4f5fSWarner Losh end 257088b4f5fSWarner Losh 258088b4f5fSWarner Losh if (m == nil) then 259088b4f5fSWarner Losh m = menu.welcome; 260088b4f5fSWarner Losh end 261088b4f5fSWarner Losh 262088b4f5fSWarner Losh -- redraw screen 263088b4f5fSWarner Losh screen.clear(); 264088b4f5fSWarner Losh screen.defcursor(); 265088b4f5fSWarner Losh local alias_table = drawer.drawscreen(m); 266088b4f5fSWarner Losh 267088b4f5fSWarner Losh-- menu.autoboot(); 268088b4f5fSWarner Losh 269088b4f5fSWarner Losh cont = true; 270088b4f5fSWarner Losh while cont do 271abc4f7e7SKyle Evans local key = io.getchar(); 272088b4f5fSWarner Losh 273b458bf0dSKyle Evans -- Special key behaviors 2741504bce3SKyle Evans if ((key == core.KEY_BACKSPACE) or (key == core.KEY_DELETE)) and 2751504bce3SKyle Evans (m ~= menu.welcome) then 276abc4f7e7SKyle Evans break 277fe672a15SKyle Evans elseif (key == core.KEY_ENTER) then 278b458bf0dSKyle Evans core.boot(); 279b458bf0dSKyle Evans -- Should not return 280abc4f7e7SKyle Evans end 281abc4f7e7SKyle Evans 282abc4f7e7SKyle Evans key = string.char(key) 283088b4f5fSWarner Losh -- check to see if key is an alias 284088b4f5fSWarner Losh local sel_entry = nil; 285088b4f5fSWarner Losh for k, v in pairs(alias_table) do 286088b4f5fSWarner Losh if (key == k) then 287088b4f5fSWarner Losh sel_entry = v; 288088b4f5fSWarner Losh end 289088b4f5fSWarner Losh end 290088b4f5fSWarner Losh 291088b4f5fSWarner Losh -- if we have an alias do the assigned action: 292088b4f5fSWarner Losh if(sel_entry ~= nil) then 293a7cf0562SKyle Evans if (sel_entry.entry_type == core.MENU_ENTRY) then 294088b4f5fSWarner Losh -- run function 295088b4f5fSWarner Losh sel_entry.func(); 296a7cf0562SKyle Evans elseif (sel_entry.entry_type == core.MENU_CAROUSEL_ENTRY) then 297ada26c4aSKyle Evans -- carousel (rotating) functionality 298ada26c4aSKyle Evans local carid = sel_entry.carousel_id; 299ada26c4aSKyle Evans local caridx = menu.getCarouselIndex(carid); 300ada26c4aSKyle Evans local choices = sel_entry.items(); 301ada26c4aSKyle Evans 302aefcaa7eSKyle Evans if (#choices > 0) then 303ada26c4aSKyle Evans caridx = (caridx % #choices) + 1; 304ada26c4aSKyle Evans menu.setCarouselIndex(carid, caridx); 305*5d1e2f83SKyle Evans sel_entry.func(caridx, choices[caridx], 30684f82e46SKyle Evans choices); 307aefcaa7eSKyle Evans end 308a7cf0562SKyle Evans elseif (sel_entry.entry_type == core.MENU_SUBMENU) then 309088b4f5fSWarner Losh -- recurse 310088b4f5fSWarner Losh cont = menu.run(sel_entry.submenu()); 311a7cf0562SKyle Evans elseif (sel_entry.entry_type == core.MENU_RETURN) then 312ef625845SKyle Evans -- allow entry to have a function/side effect 313ef625845SKyle Evans if (sel_entry.func ~= nil) then 314ef625845SKyle Evans sel_entry.func(); 315ef625845SKyle Evans end 316088b4f5fSWarner Losh -- break recurse 317088b4f5fSWarner Losh cont = false; 318088b4f5fSWarner Losh end 319088b4f5fSWarner Losh -- if we got an alias key the screen is out of date: 320088b4f5fSWarner Losh screen.clear(); 321088b4f5fSWarner Losh screen.defcursor(); 322088b4f5fSWarner Losh alias_table = drawer.drawscreen(m); 323088b4f5fSWarner Losh end 324088b4f5fSWarner Losh end 325088b4f5fSWarner Losh 326088b4f5fSWarner Losh if (m == menu.welcome) then 327088b4f5fSWarner Losh screen.defcursor(); 328088b4f5fSWarner Losh print("Exiting menu!"); 329088b4f5fSWarner Losh return false; 330088b4f5fSWarner Losh end 331088b4f5fSWarner Losh 332088b4f5fSWarner Losh return true; 333088b4f5fSWarner Loshend 334088b4f5fSWarner Losh 335088b4f5fSWarner Loshfunction menu.skip() 336088b4f5fSWarner Losh if core.bootserial() then 337088b4f5fSWarner Losh return true; 338088b4f5fSWarner Losh end 339088b4f5fSWarner Losh local c = string.lower(loader.getenv("console") or ""); 340088b4f5fSWarner Losh if (c:match("^efi[ ;]") or c:match("[ ;]efi[ ;]")) ~= nil then 341088b4f5fSWarner Losh return true; 342088b4f5fSWarner Losh end 343088b4f5fSWarner Losh 344088b4f5fSWarner Losh c = string.lower(loader.getenv("beastie_disable") or ""); 345088b4f5fSWarner Losh print("beastie_disable", c); 346088b4f5fSWarner Losh return c == "yes"; 347088b4f5fSWarner Loshend 348088b4f5fSWarner Losh 349088b4f5fSWarner Loshfunction menu.autoboot() 350088b4f5fSWarner Losh if menu.already_autoboot == true then 351088b4f5fSWarner Losh return; 352088b4f5fSWarner Losh end 353088b4f5fSWarner Losh menu.already_autoboot = true; 354088b4f5fSWarner Losh 355088b4f5fSWarner Losh local ab = loader.getenv("autoboot_delay"); 356088b4f5fSWarner Losh if ab == "NO" or ab == "no" then 357088b4f5fSWarner Losh core.boot(); 358088b4f5fSWarner Losh end 359088b4f5fSWarner Losh ab = tonumber(ab) or 10; 360088b4f5fSWarner Losh 361088b4f5fSWarner Losh local x = loader.getenv("loader_menu_timeout_x") or 5; 362088b4f5fSWarner Losh local y = loader.getenv("loader_menu_timeout_y") or 22; 363088b4f5fSWarner Losh 364088b4f5fSWarner Losh local endtime = loader.time() + ab; 365088b4f5fSWarner Losh local time; 366088b4f5fSWarner Losh 367088b4f5fSWarner Losh repeat 368088b4f5fSWarner Losh time = endtime - loader.time(); 369088b4f5fSWarner Losh screen.setcursor(x, y); 370088b4f5fSWarner Losh print("Autoboot in "..time.." seconds, hit [Enter] to boot" 371088b4f5fSWarner Losh .." or any other key to stop "); 372088b4f5fSWarner Losh screen.defcursor(); 373088b4f5fSWarner Losh if io.ischar() then 374088b4f5fSWarner Losh local ch = io.getchar(); 375fe672a15SKyle Evans if ch == core.KEY_ENTER then 376088b4f5fSWarner Losh break; 377088b4f5fSWarner Losh else 378088b4f5fSWarner Losh -- prevent autoboot when escaping to interpreter 379088b4f5fSWarner Losh loader.setenv("autoboot_delay", "NO"); 380088b4f5fSWarner Losh -- erase autoboot msg 381088b4f5fSWarner Losh screen.setcursor(0, y); 382088b4f5fSWarner Losh print(" " 383088b4f5fSWarner Losh .." "); 384088b4f5fSWarner Losh screen.defcursor(); 385088b4f5fSWarner Losh return; 386088b4f5fSWarner Losh end 387088b4f5fSWarner Losh end 388088b4f5fSWarner Losh 389088b4f5fSWarner Losh loader.delay(50000); 390088b4f5fSWarner Losh until time <= 0 391088b4f5fSWarner Losh core.boot(); 392088b4f5fSWarner Losh 393088b4f5fSWarner Loshend 394088b4f5fSWarner Losh 395088b4f5fSWarner Loshfunction OnOff(str, b) 396088b4f5fSWarner Losh if (b) then 397088b4f5fSWarner Losh return str .. color.escapef(color.GREEN).."On"..color.escapef(color.WHITE); 398088b4f5fSWarner Losh else 399088b4f5fSWarner Losh return str .. color.escapef(color.RED).."off"..color.escapef(color.WHITE); 400088b4f5fSWarner Losh end 401088b4f5fSWarner Loshend 402088b4f5fSWarner Losh 403088b4f5fSWarner Loshreturn menu 404